<?php

/* ######################################################################

  IML DEPLOYMENT

  class formgen - (copied and improved from simap prototype project)
  It generates Form elements. This class does what I need it is not
  feature complete.

  ---------------------------------------------------------------------
  2013-11-08  Axel <axel.hahn@iml.unibe.ch>
  ###################################################################### */

class formgen {

    var $aForm = array();
    var $sRequired = ' <span title="Eingabe ist erforderlich"><span style="color:#c00;">*</span></span>';

    /**
     * constructor
     * @param array $aNewFormData
     * @return boolean
     */
    public function __construct($aNewFormData = array()) {
        if (count($aNewFormData)){
            return $this->setFormarray($aNewFormData);
        }
        return true;
    }

    /**
     * set a new array
     * @param array $aNewFormData
     * @return boolean
     */
    public function setFormarray($aNewFormData = array()) {
        if (!is_array($aNewFormData) || !count($aNewFormData)) {
            return false;
        }
        return $this->aForm = $aNewFormData;
    }

    /**
     * get html code for a completely rendered form
     * @param string $sFormId
     * @return string html output
     */
    public function renderHtml($sFormId) {
        $sReturn = false;
        if (!array_key_exists($sFormId, $this->aForm)) {
            die("ERROR: " . __CLASS__ . ":" . __FUNCTION__ . " - form id " . $sFormId . " does not exist.");
        }
        // FORM tag
        $sReturn.='<form ';
        if (array_key_exists("meta", $this->aForm[$sFormId])) {
            foreach (array("method", "action", "target", "accept-charset", "class", "id", "name") as $sAttr) {
                if (array_key_exists($sAttr, $this->aForm[$sFormId]["meta"])) {
                    $sReturn.=$sAttr . '="' . $this->aForm[$sFormId]["meta"][$sAttr] . '" ';
                }
            }
        }
        $sReturn.='>';
        
        // ... and all its elements
        foreach ($this->aForm[$sFormId]["form"] as $elementKey => $elementData) {
            $sReturn.=$this->renderHtmlElement($elementKey, $elementData);
        }
        $sReturn.='</form>';

        return $sReturn;
    }

    /**
     * add html attributes if they exist
     * @param array $aAttributes  list of attributes to search for
     * @param array $elementData  array of form element
     * @return string
     */
    private function _addHtmlAtrributes($aAttributes, $elementData) {
        $sReturn = false;
        foreach ($aAttributes as $sAtrr) {
            if (array_key_exists($sAtrr, $elementData) && $elementData[$sAtrr]) {
                if ($sReturn)
                    $sReturn.=' ';
                $sReturn.=$sAtrr . '="' . $elementData[$sAtrr] . '"';
            }
        }
        return $sReturn;
    }

    private function _addLabel($sLabel, $sFor, $sClass = false) {
        $sReturn = false;
        $sReturn = '<label for="' . $sFor . '"';
        if ($sClass)
            $sReturn.=' class="' . $sClass . '"';
        $sReturn.='>' . $sLabel . '</label>';
        $sReturn.="\n";
        return $sReturn;
    }

    private function _checkReqiredKeys($aArray, $aRequiredKeys, $sLabel = false) {
        $bReturn = true;
        foreach ($aRequiredKeys as $sKey) {
            if (!array_key_exists($sKey, $aArray)) {
                die("ERROR: $sLabel<br>Missing key \"$sKey\" in the array of a form element:<pre>" . print_r($aArray, true) . "</pre>");
                $bReturn = false;
            }
        }
        return $bReturn;
    }

    /**
     * render a single form element
     * @param string $sId          id of a form element
     * @param array  $elementData  array of form element
     * @return string html output
     */
    public function renderHtmlElement($sId, $elementData) {
        $sReturn = false;
        $aAllowedHtmlAttributes = array();
        $sDefaultAttributes = "class,onclick,onmouseover,onmouseout,title";

        if (!array_key_exists("type", $elementData)) {
            print_r($elementData);
            die("ERROR: " . __CLASS__ . ":" . __FUNCTION__ . " - key &quot;type&quot; does not exist.");
        }

        $sFormElement = false;
        $sLabelText = '';
        $sLabelElement = false;

        $sHtmlDefault = '';
        $sHtmlTable = '';

        if (array_key_exists("label", $elementData)) {
            $sLabelText = $elementData["label"];
            $sLabelText.=(array_key_exists("required", $elementData) && $elementData["required"]) ? $this->sRequired : '';
        }

        switch ($elementData["type"]) {
            case "button":
                $this->_checkReqiredKeys($elementData, array("value"));
                $sFormElement.='    <button id="' . $sId . '" class="btn btn-default"';
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,checked,name"), $elementData);
                $sFormElement.='>' . $elementData["value"] . '</button>';
                $sFormElement.="\n";

                $sHtmlDefault = $sFormElement;
                break;

            case "checkbox":
                $this->_checkReqiredKeys($elementData, array("name"));
                foreach ($elementData["options"] as $idOption => $aOptionData) {
                    $sFormElement.="\n".'<div class="checkbox">';
                    $s = preg_replace('/\W/iu', '', $sId . $idOption);
                    $sOptionId = preg_replace('/[äöüß]/i', '', $s);
                    $sFormElement.='    <input type="checkbox" id="' . $sOptionId . '" value="' . $idOption . '" ';
                    $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,checked"), $aOptionData);
                    $sFormElement.=' name="' . $elementData["name"] . '[]"';
                    $sFormElement.='/><label for="' . $sOptionId . '">' . $aOptionData["label"] . '</label></div>';
                }
                $sFormElement.="\n";
                // $sLabelElement.='<span class="help-block">' . $sLabelText . '</span>';
                $sLabelElement.='<div class="col-sm-2">' . $sLabelText . '</div>';
                $sLabelElement.="\n";

                // $sHtmlDefault = $sLabelElement . $sFormElement;
                $sHtmlDefault = $sLabelElement . '<div class="col-sm-10">' . "\n" . $sFormElement . '</div>' . "\n";
                $sHtmlTable = '<td>' . $sLabelText . '</td><td>' . $sFormElement . '</td>';
                break;

            case "hidden":
                $this->_checkReqiredKeys($elementData, array("value"));
                $sFormElement.='    <input type="hidden" id="' . $sId . '" ';
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "name,value"), $elementData);
                $sFormElement.=" />";
                $sFormElement.="\n";

                $sHtmlDefault = $sFormElement . "\n";
                break;

            case "markup":
                if (array_key_exists("value", $elementData))
                    $sHtmlDefault = $elementData["value"] . "\n";
                break;

            case "radio":
                $this->_checkReqiredKeys($elementData, array("name"));
                foreach ($elementData["options"] as $idOption => $aOptionData) {
                    $sFormElement.="\n".'<div class="radio">';
                    $s = preg_replace('/\W/iu', '', $sId . $idOption);
                    $sOptionId = preg_replace('/[äöüß]/i', '', $s);
                    $sFormElement.='    <input type="radio" id="' . $sOptionId . '" value="' . $idOption . '" ';
                    $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,checked"), $aOptionData);
                    $sFormElement.=" " . $this->_addHtmlAtrributes(explode(",", "name"), $elementData);
                    $sFormElement.='/><label for="' . $sOptionId . '">' . $aOptionData["label"] . '</label></div>';
                }
                $sFormElement.="\n";

                if ($sLabelText) {
                    // $sLabelElement.='<span class="help-block">' . $sLabelText . '</span>' . "\n";
                    $sLabelElement = $this->_addLabel($sLabelText, $sId, "col-sm-2");
                }

                // $sHtmlDefault = $sLabelElement . $sFormElement;
                $sHtmlDefault = $sLabelElement . '<div class="col-sm-10">' . "\n" . $sFormElement . '</div>' . "\n";

                $sHtmlTable = '<td>' . $sLabelText . '</td><td>' . $sFormElement . '</td>';
                // $sHtmlDefault = $sLabelElement . $sFormElement;

                // $sReturn.=$this->_addLabel($sFormElement,$sId,"checkbox");
                break;

            case "select":
                // HINWEIS optgroups werden nicht unterstuezt - nur einfache Listen
                $this->_checkReqiredKeys($elementData, array("name"));
                $sDivClass=(array_key_exists("inline", $elementData) && $elementData["inline"])?"form-group":"col-sm-10";
                $sFormElement.='<div class="'.$sDivClass.'"><select id="' . $sId . '" class="form-control" ';
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,name,onchange"), $elementData);
                $sFormElement.=">\n";
                foreach ($elementData["options"] as $idOption => $aOptionData) {
                    $s = preg_replace('/\W/iu', '', $sId . $idOption);
                    $sOptionId = preg_replace('/[äöüß]/i', '', $s);
                    $sFormElement.='    <option value="' . $idOption . '" ';
                    $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,selected"), $aOptionData);
                    $sFormElement.='>' . $aOptionData["label"] . '</option>' . "\n";
                }
                $sFormElement.="</select></div>\n";

                if ($sLabelText) {
                    // $sLabelElement.='<span class="help-block">' . $sLabelText . '</span>' . "\n";
                    $sLabelClass=(array_key_exists("inline", $elementData) && $elementData["inline"])?"":"col-sm-2";
                    $sLabelElement = $this->_addLabel($sLabelText, $sId, $sLabelClass);
                }

                $sHtmlTable = '<td>' . $sLabelText . '</td><td>' . $sFormElement . '</td>';
                $sHtmlDefault = $sLabelElement . $sFormElement;

                // $sReturn.=$this->_addLabel($sFormElement,$sId,"checkbox");
                break;

            case "submit":
                $this->_checkReqiredKeys($elementData, array("value"));
                $sClass="btn btn-primary ";
                if (array_key_exists("class", $elementData)){
                    $sClass.=$elementData["class"];
                }
                $elementData["class"]=$sClass;
                $sFormElement.='    <button id="' . $sId . '" type="submit" ';
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes"), $elementData);
                $sFormElement.='>' . $elementData["value"] . '</button>';
                $sFormElement.="\n";

                $sHtmlDefault = $sFormElement;
                break;

            case "text":
            case "password":
                $this->_checkReqiredKeys($elementData, array("name"));
                $sFormElement.='    <input type="'.$elementData["type"].'" id="' . $sId . '" class="form-control col-sm-10" ';
                $aAllowedHtmlAttributes["text"] = explode(",", "");
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,name,list,disabled,onkeyup,onkeydown,onchange,pattern,placeholder,required,size,value"), $elementData);
                // $sFormElement.=$this->_addHtmlAtrributes(array("name", "value", "size", "placeholder", "required"), $elementData);
                // IE: Return abfangen lassen
                // $sFormElement.=' onkeypress="return checkKey(event);"';
                $sFormElement.=' />';
                $sFormElement.="\n";

                if (array_key_exists("inline", $elementData) && $elementData["inline"]){
                    $sLabelElement = $this->_addLabel($sLabelText, $sId, "col-sm-2");
                    // $sHtmlDefault = $sLabelElement . "\n" . $sFormElement . "\n";
                    $sHtmlDefault = $sLabelElement . '<div class="col-sm-2">' . "\n" . $sFormElement . '</div>' . "\n";                    
                } else {
                    $sLabelElement = $this->_addLabel($sLabelText, $sId, "col-sm-2");
                    // $sHtmlDefault = $sLabelElement . '<div class="controls">' . "\n" . $sFormElement . '</div>' . "\n";                    
                    $sHtmlDefault = $sLabelElement . '<div class="col-sm-10">' . "\n" . $sFormElement . '</div>' . "\n";                    
                }

                $sHtmlTable = '<td>' . $sLabelText . '</td><td>' . $sFormElement . '</td>';

                break;

            case "textarea":
                $this->_checkReqiredKeys($elementData, array("name"));
                $sFormElement.='    <textarea id="' . $sId . '" ';
                $aAllowedHtmlAttributes["text"] = explode(",", "");
                $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,name,onkeyup,onkeydown,onchange,placeholder,required,cols,rows"), $elementData);
                // $sFormElement.=$this->_addHtmlAtrributes(array("name", "value", "size", "placeholder", "required"), $elementData);
                $sFormElement.='></textarea>';
                $sFormElement.="\n";

                $sLabelElement = $this->_addLabel($sLabelText, $sId, "control-label col-sm-2");

                // $sHtmlDefault = $sLabelElement . '<div class="controls">' . "\n" . $sFormElement . '</div>' . "\n";
                $sHtmlDefault = $sLabelElement . '<div class=" col-sm-10">' . "\n" . $sFormElement . '</div>' . "\n";
                $sHtmlTable = '<td>' . $sLabelElement . '</td><td>' . $sFormElement . '</td>';

                break;

            default:
                die("ERROR: " . __CLASS__ . ":" . __FUNCTION__ . " - formelement type " . $elementData["type"] . " ist not supported (yet).");
                break;
        }

        // Default or table mode?
        if (array_key_exists("mode", $elementData) && $elementData["mode"] == 'table' && $sHtmlTable) {
            $sHtmlDefault = $sHtmlTable;
        } else {
            if ($elementData["type"] != "button" && $elementData["type"] != "fieldset" && $elementData["type"] != "markup") {
                if (!array_key_exists("inline", $elementData) || !$elementData["inline"]){
                    // $sHtmlDefault = "<fieldset>" . $sHtmlDefault . "</fieldset>\n";
                    $sHtmlDefault = '<div class="form-group">' . $sHtmlDefault . '</div>'."\n";
                }
            }
        }

        $sReturn.="<!-- " . $elementData["type"] . " -->\n";
        $sReturn.=$sHtmlDefault . "\n";

        return $sReturn;
    }

}

?>