<?PHP
#
#   FILE:  FormUI.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2016 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

/**
* Child class (covering presentation elements only) supplying a standard user
* interface for presenting and working with HTML forms.
*/
class FormUI extends FormUI_Base
{

    # ---- PUBLIC INTERFACE --------------------------------------------------

    /**
    * Display HTML table for form.
    * @param string $TableId CSS ID for table element.  (OPTIONAL)
    * @param string $TableStyle CSS styles for table element.  (OPTIONAL)
    */
    public function DisplayFormTable($TableId = NULL, $TableStyle = NULL)
    {
        # display nothing if there are no fields
        if (!count($this->FieldParams)) {  return;  }

        # check whether table should be split into sections
        $TableIsSectioned = FALSE;
        foreach ($this->FieldParams as $Name => $Params)
        {
            if ($Params["Type"] == self::FTYPE_HEADING)
                    {  $TableIsSectioned = TRUE;  }
        }

        # begin table
        // @codingStandardsIgnoreStart
        ?><table class="cw-table cw-table-fullsize cw-table-sideheaders cw-table-padded
          cw-table-striped <?PHP
        if ($TableIsSectioned) {  print(" cw-table-sectioned");  }
        ?> cw-content-sysconfigtable"<?PHP
        if ($TableId) {  print(" id=\"".$TableId."\"");  }
        if ($TableStyle) {  print(" style=\"".$TableStyle."\"");  }
        ?>>
        <tbody><?PHP
        // @codingStandardsIgnoreEnd

        # for each field
        foreach ($this->FieldParams as $Name => $Params)
        {
            # if field is actually a section heading
            if ($Params["Type"] == self::FTYPE_HEADING)
            {
                # split table section and display heading
                if (isset($HeadingAlreadyDisplayed)) {  print("</tbody><tbody>");  }
                ?><tr><th colspan="3" scope="rowspan"><?PHP
                print($Params["Label"]);
                $HeadingAlreadyDisplayed = TRUE;
                ?></th></tr><?PHP
            }
            else
            {
                # determine if row may have taller content
                $IsTallRow = !isset($Params["Units"])
                        && !in_array($Params["Type"],
                                array("Flag", "Text", "Number", "User"))
                        && (($Params["Type"] != "Option")
                                || (isset($Params["Rows"])
                                        && ($Params["Rows"] > 1)));

                # load up value(s) to go into field
                $Value = $this->GetFieldValue($Name);

                $FormFieldName = $this->GetFormFieldName($Name);

                # set up CSS classes for table row
                $RowClass = "cw-formui-fieldtype-".strtolower($Params["Type"]);
                if ($Params["Type"] == "MetadataField")
                {
                    $RowClass .= " cw-formui-schemaid-"
                            .GetArrayValue($Params, "SchemaId",
                                    MetadataSchema::SCHEMAID_DEFAULT);
                }
                $RowClass .= $IsTallRow ? " cw-content-tallrow" : "";
                $RowClassAttrib = strlen($RowClass)
                        ? ' class="'.$RowClass.'"' : "";

                # set up CSS classes for row header cell
                $HeaderClass = $IsTallRow ? "cw-content-tallrow-th" : "";
                $HeaderClassAttrib = strlen($HeaderClass)
                        ? ' class="'.$HeaderClass.'"' : "";

                # set up CSS classes for row label
                $LabelClass = "cw-form-pseudolabel"
                        .(isset(self::$ErrorMessages[$Name])
                        ? " cw-form-error" : "");

                // @codingStandardsIgnoreStart
                ?>
                <tr valign="top"<?= $RowClassAttrib ?>>
                    <th<?= $HeaderClassAttrib ?>>
                        <label for="<?=  $FormFieldName
                                ?>" class="<?=  $LabelClass  ?>"><?=
                                $Params["Label"]  ?></label>
                    </th>
                    <td <?PHP  if (!isset($Params["Help"])) {
                                    print "colspan=\"2\"";  }  ?>><?PHP
                            $this->DisplayFormField(
                                    $Name, $Value, $Params);  ?></td>
                    <?PHP  if (isset($Params["Help"])) {  ?>
                    <td class="cw-content-help-cell"><?PHP
                            print $Params["Help"];  ?></td>
                    <?PHP  }  ?>
                </tr>
                <?PHP
            }
        }

        # end table
        ?></tbody>
        </table><?PHP

        # add any hidden form fields
        print $this->GetHiddenFieldsHtml();

        # pull in WYSIWYG editor setup if needed
        if ($this->UsingWysiwygEditor)
        {
            require_once($GLOBALS["AF"]->GUIFile("CKEditorSetup.php"));
        }
    }
    // @codingStandardsIgnoreEnd

    /**
    * Display HTML block with error messages (if any).
    */
    public static function DisplayErrorBlock()
    {
        if (count(self::$ErrorMessages))
        {
            print "<ul class=\"cw-form-error\">\n";
            foreach (self::$ErrorMessages as $Field => $Msgs)
            {
                foreach ($Msgs as $Msg)
                {
                    print "<li>".$Msg."</li>\n";
                }
            }
            print "</ul>\n";
        }
    }


    # ---- PRIVATE INTERFACE -------------------------------------------------

    protected $UsingWysiwygEditor = FALSE;


    /**
    * Display HTML form field for specified field.
    * @param string $Name Field name.
    * @param mixed $Value Current value for field.
    * @param array $Params Field parameters.
    */
    protected function DisplayFormField($Name, $Value, $Params)
    {
        $FieldName = $this->GetFormFieldName($Name);

        switch ($Params["Type"])
        {
            case self::FTYPE_TEXT:
            case self::FTYPE_NUMBER:
            case self::FTYPE_URL:
            case self::FTYPE_USER:
                if ($Params["Type"] == self::FTYPE_USER)
                {
                    if (is_numeric($Value))
                    {
                        $User = new CWUser($Value);
                        $Value = $User->Name();
                    }
                }
                $DefaultSize = ($Params["Type"] == self::FTYPE_NUMBER) ? 6 : 40;
                $DefaultMaxLen = ($Params["Type"] == self::FTYPE_NUMBER) ? 12 : 80;
                $Size = isset($Params["Size"]) ? $Params["Size"]
                        : (isset($Params["MaxVal"])
                            ? (strlen(intval($Params["MaxVal"]) + 1))
                            : $DefaultSize);
                $MaxLen = isset($Params["MaxLength"]) ? $Params["MaxLength"]
                        : (isset($Params["MaxVal"])
                            ? (strlen(intval($Params["MaxVal"]) + 3))
                            : $DefaultMaxLen);
                $Placeholder = isset($Params["Placeholder"])
                        ? $Params["Placeholder"]
                        : "(".strtolower($Params["Label"]).")";
                print('<input type="text" size="'.$Size.'" maxlength="'
                        .$MaxLen.'" id="'.$FieldName.'" name="'.$FieldName.'"'
                        .' value="'.htmlspecialchars($Value).'"'
                        .' placeholder=" '.htmlspecialchars($Placeholder).'"'
                        .($Params["ReadOnly"] ? " readonly" : "").' />');
                break;

            case self::FTYPE_PARAGRAPH:
                $Rows = isset($Params["Rows"]) ? $Params["Rows"] : 4;
                $Columns = isset($Params["Columns"]) ? $Params["Columns"] : 40;
                print('<textarea rows="'.$Rows.'" cols="'.$Columns
                        .'" id="'.$FieldName.'" name="'.$FieldName.'"'
                        .($Params["ReadOnly"] ? " readonly" : "")
                        .($Params["UseWYSIWYG"] ? ' class="ckeditor"' : "").'>'
                        .htmlspecialchars($Value)
                        .'</textarea>');
                if ($Params["UseWYSIWYG"])
                {
                    $this->UsingWysiwygEditor = TRUE;
                }
                break;

            case self::FTYPE_FLAG:
                if (array_key_exists("OnLabel", $Params)
                        && array_key_exists("OffLabel", $Params))
                {
                    print('<input type="radio" id="'.$FieldName.'On" name="'
                            .$FieldName.'" value="1"'
                            .($Value ? ' checked' : '')
                            .($Params["ReadOnly"] ? ' disabled' : '')
                            .' /> <label for="'.$FieldName.'On">'.$Params["OnLabel"]
                            ."</label>\n");
                    print('<input type="radio" id="'.$FieldName.'Off" name="'
                            .$FieldName.'" value="0"'
                            .($Value ? '' : ' checked')
                            .($Params["ReadOnly"] ? ' disabled' : '')
                            .' /> <label for="'.$FieldName.'Off">'.$Params["OffLabel"]
                            ."</label>\n");
                }
                else
                {
                    print('<input type="checkbox" id="'.$FieldName.'" name="'
                            .$FieldName.'" '
                            .($Value ? ' checked' : '')
                            .($Params["ReadOnly"] ? ' disabled' : '')
                            ." />\n");
                }
                break;

            case self::FTYPE_OPTION:
                $OptList = new HtmlOptionList(
                        $FieldName, $Params["Options"], $Value);
                $OptList->MultipleAllowed($Params["AllowMultiple"]);
                $OptList->Size(isset($Params["Rows"]) ? $Params["Rows"] : 1);
                $OptList->Disabled($Params["ReadOnly"]);
                $OptList->PrintHtml();
                break;

            case self::FTYPE_METADATAFIELD:
                $FieldTypes = GetArrayValue($Params, "FieldTypes");
                $SchemaId = GetArrayValue($Params, "SchemaId",
                        MetadataSchema::SCHEMAID_DEFAULT);
                $Schema = new MetadataSchema($SchemaId);
                print $Schema->GetFieldsAsOptionList(
                        $FieldName, $FieldTypes, $Value,
                        !$Params["AllowMultiple"], NULL,
                        $Params["AllowMultiple"], $Params["ReadOnly"]);
                break;

            case self::FTYPE_PRIVILEGES:
                $PFactory = new PrivilegeFactory();
                $PrivilegeNames = $PFactory->GetItemNames();
                $OptList = new HtmlOptionList(
                        $FieldName, $PrivilegeNames, $Value);
                $OptList->MultipleAllowed($Params["AllowMultiple"]);
                $OptList->Size(isset($Params["Rows"])
                        ? $Params["Rows"]
                        : ($Params["AllowMultiple"] ? 15 : 1));
                $OptList->Disabled($Params["ReadOnly"]);
                $OptList->PrintHtml();
                break;

            case self::FTYPE_IMAGE:
                $this->DisplayImageField($FieldName, $Value, $Params);
                break;
        }

        if (isset($Params["Units"]))
        {
            ?>&nbsp;<span><?PHP
            print $Params["Units"];
            ?></span><?PHP
        }
    }

    /**
    * Display image form field for specified field.
    * @param string $FieldName Field name.
    * @param mixed $Value Current value for field.
    * @param array $Params Field parameters.
    */
    protected function DisplayImageField($FieldName, $Value, $Params)
    {
        # normalize incoming value
        $Images = is_array($Value) ? $Value
                : (($Value === NULL) ? array() : array($Value));

        # begin value table
        print '<table border="0" cellspacing="0" cellpadding="0" width="100%">';

        # for each incoming value
        $ImagesDisplayed = 0;
        $InsertButtonHtml = "";
        foreach ($Images as $Image)
        {
            # skip if image is a placeholder to indicate no images for field
            if ($Image == self::NO_VALUE_FOR_FIELD)
            {
                continue;
            }

            # load up image object if ID supplied
            if (is_numeric($Image))
            {
                $Image = new SPTImage($Image);
            }

            # skip image if it has been deleted
            if (in_array($Image->Id(), $this->DeletedImages))
            {
                continue;
            }

            # load various image attributes for use in HTML
            $ImageUrl = defaulthtmlentities($Image->ThumbnailUrl());
            $ImageId = $Image->Id();
            $ImageAltTextFieldName = $FieldName."_AltText_".$ImageId;
            $ImageAltText = defaulthtmlentities(
                    isset($_POST[$ImageAltTextFieldName])
                    ? $_POST[$ImageAltTextFieldName]
                    : $Image->AltText());

            # build up HTML for any insert buttons
            if (isset($Params["InsertIntoField"]))
            {
                $InsertField = $this->GetFormFieldName($Params["InsertIntoField"]);
                $InsertRightCommand = defaulthtmlentities(
                        "CKEDITOR.instances['".$InsertField
                                ."'].insertHtml("
                        ."'<img src=\"".$Image->PreviewUrl()."\" alt=\""
                        .htmlspecialchars($Image->AltText())
                        ."\" class=\"cw-formui-image-right\" />');");
                $InsertLeftCommand = defaulthtmlentities(
                        "CKEDITOR.instances['".$InsertField
                                ."'].insertHtml("
                        ."'<img src=\"".$Image->PreviewUrl()."\" alt=\""
                        .htmlspecialchars($Image->AltText())
                        ."\" class=\"cw-formui-image-left\" />');");
                $InsertButtonHtml = '<button type="button" onclick="'
                        .$InsertLeftCommand.'">Insert-L</button>'
                        .'<button type="button" onclick="'
                        .$InsertRightCommand.'">Insert-R</button>';
            }

            # add table row for image
            ?><tr>
                <td><img src="<?= $ImageUrl ?>"></td>
                <td style="white-space: nowrap;"><label for="<?=
                        $ImageAltTextFieldName ?>" class="cw-form-pseudolabel">
                        Alt Text:</label><input type="text" size="20"
                        maxlength="120" name="<?= $ImageAltTextFieldName ?>"
                        value="<?= $ImageAltText ?>"
                        placeholder=" (alternate text for image)"></td>
                <td><?= $InsertButtonHtml ?><input type="submit" name="Submit"
                        onclick="$('#F_ImageToDelete').val('<?= $ImageId
                        ?>');" value="Delete"></td>
            </tr><?PHP
            $ImagesDisplayed++;

            # add image ID to hidden fields
            $this->HiddenFields[$FieldName."_ID"][] = $Image->Id();

            # add container to hold ID of any image to be deleted
            if (!isset($this->HiddenFields["F_ImageToDelete"]))
            {
                $this->HiddenFields["F_ImageToDelete"] = "";
            }
        }

        # if no images were displayed and an image entry was skipped
        if (($ImagesDisplayed == 0) && count($Images))
        {
            # add marker to indicate no images to hidden fields
            $this->HiddenFields[$FieldName."_ID"][] = self::NO_VALUE_FOR_FIELD;
        }

        # add table row for new image upload
        if ($Params["AllowMultiple"] || ($ImagesDisplayed == 0))
        {
            $ImageAltTextFieldName = $FieldName."_AltText_NEW";
            ?><tr>
                <td><input type="file" name="<?= $FieldName ?>" /></td>
                <td style="white-space: nowrap;"><label for="<?=
                        $ImageAltTextFieldName ?>" class="cw-form-pseudolabel">
                        Alt Text:</label><input type="text" size="20"
                        maxlength="120" name="<?= $ImageAltTextFieldName ?>"
                        placeholder=" (alternate text for image)"></td>
                <td><input type="submit" name="Submit" value="Upload" /></td>
            </tr><?PHP
        }

        # end value table
        print '</table>';
    }
}
