<?php
/**
 * BoxBilling
 *
 * @copyright BoxBilling, Inc (https://www.boxbilling.org)
 * @license   Apache-2.0
 *
 * Copyright BoxBilling, Inc
 * This source file is subject to the Apache-2.0 License that is bundled
 * with this source code in the file LICENSE
 */


namespace Box\Mod\Formbuilder;
use Box\InjectionAwareInterface;

class Service implements InjectionAwareInterface
{
    /**
     * @var \Box_Di
     */
    protected $di = null;

    /**
     * @param \Box_Di $di
     */
    public function setDi($di)
    {
        $this->di = $di;
    }

    /**
     * @return \Box_Di
     */
    public function getDi()
    {
        return $this->di;
    }


    public function getFormFieldsTypes()
    {
        return array(
            "text" => 'Text input',
            "select" => 'Dropdown',
            "radio" => 'Radio select',
            "checkbox" => 'Checkbox',
            "textarea" => 'Text area'
        );
    }

    public function typeValidation($type)
    {
        return array_key_exists($type, $this->getFormFieldsTypes());
    }

    public function isArrayUnique($data)
    {
        $unique = array_unique($data);
        return (count($data) === count($unique));

    }

    public function addNewForm($data)
    {
        $data["style"]["type"] = isset ($data["type"])? $data["type"] : "horizontal";
        $data["style"]["show_title"] = isset ($data["show_title"])? $data["show_title"] : "0";
        $data["style"] = json_encode($data["style"],JSON_FORCE_OBJECT);

        $bean = $this->di['db']->dispense('Form');
        $bean->name = $data['name'];
        $bean->style =  $data['style'];
        $bean->created_at = date('Y-m-d H:i:s');
        $bean->updated_at = date('Y-m-d H:i:s');

        $form_id = $this->di['db']->store($bean);
        $this->di['logger']->info('Created new form %s with id %s', $data['name'], $form_id);
        return $form_id;
    }

    public function addNewField($field) //TODO server-side required check
    {
        $field_number = (int)$this->getFormFieldsCount($field['form_id']) + 1;

        $formId = $field['form_id'];
        $types = $this->getFormFieldsTypes();
        $type = $field["type"];

        $label = $this->di['array_get']($field, 'label', $types[$type] . " " . $field_number);
        $name  = $this->di['array_get']($field, 'name', ($this->slugify("new_" . $type) . "_" . $field_number));

        if ($type == "select" || $type == "checkbox" || $type == "radio") {
            $field['options'] = '{"First option":"1", "Second option": "2", "Third option":"3"}';
        }
        if ($field['type'] == "textarea" && !isset($field['options'])) {
            $field['options'] = '{"height":"100", "width": "300"}';
        }
        if (isset($field['default_value'])) {
            $field['default_value'] = is_array($field['default_value']) ? json_encode($field['default_value'], JSON_FORCE_OBJECT) : $field['default_value'];
        }
        if (isset ($field['options']) && is_array($field['options'])) {
            $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
        }
        $bean = $this->di['db']->dispense('FormField');
        $bean->form_id = $formId;
        $bean->name = $name;
        $bean->label = $label;
        $bean->hide_label = $this->di['array_get']($field, 'hide_label', null);
        $bean->description = $this->di['array_get']($field, 'description', null);
        $bean->type = $field['type'];
        $bean->default_value = $this->di['array_get']($field, 'default_value', null);
        $bean->required = $this->di['array_get']($field, 'required', null);
        $bean->hidden = $this->di['array_get']($field, 'hidden', null);
        $bean->readonly = $this->di['array_get']($field, 'readonly', null);
        $bean->options = $this->di['array_get']($field, 'options', null);
        $bean->prefix = $this->di['array_get']($field, 'prefix', null);
        $bean->suffix = $this->di['array_get']($field, 'suffix', null);
        $bean->show_initial = $this->di['array_get']($field, 'show_initial', null);
        $bean->show_middle = $this->di['array_get']($field, 'show_middle', null);
        $bean->show_prefix = $this->di['array_get']($field, 'show_prefix', null);
        $bean->show_suffix = $this->di['array_get']($field, 'show_suffix', null);
        $bean->text_size = $this->di['array_get']($field, 'text_size', null);
        $bean->created_at = date('Y-m-d H:i:s');
        $bean->updated_at = date('Y-m-d H:i:s');

        $fieldId = $this->di['db']->store($bean);
        $this->di['logger']->info('Added new field %s to form %s', $fieldId, $field['form_id']);

        return $fieldId;
    }


    private function slugify($text)
    {

        // replace non letter or digits by _
        $text = preg_replace('~[^\\pL\d]+~u', '_', $text);

        // trim
        $text = trim($text, '_');

        // transliterate
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);

        // lowercase
        $text = strtolower($text);

        // remove unwanted characters
        $text = preg_replace('~[^-\w]+~', '', $text);

        if (is_numeric(substr($text, 0, 1))) {
            throw new \Box_Exception ('Field name can not start with number.', null, 1649);
        }

        if (empty($text)) {
            throw new \Box_Exception ('Field name can not be empty. Please make sure it is not empty and does not contain special characters.', null, 3502);
        }

        return $text;
    }


    public function updateField($field)
    {
        $fieldId = $field['id'];

        $label = isset($field['label']) ? $field['label'] : 'New field';
        $name = $this->slugify($field['name']);

        $get_field = $this->getField($field['id']);
        $field['form_id'] = $get_field['form_id'];

        if ($this->formFieldNameExists(array("form_id" => $field["form_id"], "field_name" => $field["name"], "field_id" => $fieldId))) {
            throw new \Box_Exception ('Unfortunately field with this name exists in this form already. Form must have different field names.', null, 7628);
        }

        $field['options'] = isset($field['options']) ? json_encode($field['options']) : "";
        if (isset($field['default_value'])) {
            $field['default_value'] = is_array($field['default_value']) ? json_encode($field['default_value'], JSON_FORCE_OBJECT) : $field['default_value'];
        }

        if (isset($field['type'])) {
            if ($field['type'] == "checkbox" || $field['type'] == "radio" || $field['type'] == "select") {
                if (!$this->isArrayUnique(array_filter($field['values'], 'strlen'))) {
                    throw new \Box_Exception(ucfirst($field['type']) . ' values must be unique', null, 1597);
                }
                if (!$this->isArrayUnique(array_filter($field['labels'], 'strlen'))) {
                    throw new \Box_Exception(ucfirst($field['type']) . ' labels must be unique', null, 1598);
                }
                $field['options'] = array_combine($field['labels'], $field['values']);
                $field['options'] = array_filter($field['options'], 'strlen');
                $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
            }
            if ($field['type'] == "textarea") {
                if (count($field['textarea_size']) != count(array_filter($field['textarea_size'], 'is_numeric'))) {
                    throw new \Box_Exception('Textarea size options must be integer values', null, 3510);
                }
                $field['options'] = array_combine($field['textarea_option'], $field['textarea_size']);
                $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
            }
        }

        $bean = $this->di['db']->dispense('FormField');
        $bean->id = $fieldId;
        $bean->name = $name;
        $bean->label = $label;
        $bean->hide_label = $this->di['array_get']($field, 'hide_label', null);
        $bean->description = $this->di['array_get']($field, 'description', null);
        $bean->default_value = $this->di['array_get']($field, 'default_value', null);
        $bean->required = $this->di['array_get']($field, 'required', null);
        $bean->hidden = $this->di['array_get']($field, 'hidden', null);
        $bean->readonly = $this->di['array_get']($field, 'readonly', null);
        $bean->options = $field['options'];
        $bean->prefix = $this->di['array_get']($field, 'prefix', null);
        $bean->suffix = $this->di['array_get']($field, 'suffix', null);
        $bean->show_initial = $this->di['array_get']($field, 'show_initial', null);
        $bean->show_middle = $this->di['array_get']($field, 'show_middle', null);
        $bean->show_prefix = $this->di['array_get']($field, 'show_prefix', null);
        $bean->show_suffix = $this->di['array_get']($field, 'show_suffix', null);
        $bean->text_size = $this->di['array_get']($field, 'text_size', null);
        $bean->updated_at = date('Y-m-d H:i:s');

        $this->di['db']->store($bean);
        $this->di['logger']->info('Updated custom form %s', $fieldId);
        return $fieldId;
    }

    public function getForm($formId)
    {
        $formModel = $this->di['db']->getExistingModelById('Form', $formId);
        $result = $this->di['db']->toArray($formModel);

        $result['style'] = json_decode($result['style'], true);
        $result['fields'] = $this->getFormFields($result['id']);
        $result['fields'] = $this->fieldsJsonDecode($result['fields']);
        return $result;
    }

    public function getFormFields($formId)
    {
        $sql = ("
        SELECT *
        FROM form_field
        WHERE form_id = :form_id
        ORDER BY ID asc
        ");
        $result = $this->di['db']->getAll($sql, array(':form_id' => $formId));
        return $result;

    }

    private function fieldsJsonDecode($fields)
    {
        foreach ($fields as $key => $r) {
            $fields[$key]['options'] = json_decode($r['options'], true);
            $fields[$key]['default_value'] = (json_decode($r['default_value'])) ? (json_decode($r['default_value'], true)) : $r['default_value'];
        }
        return $fields;
    }

    public function getFormFieldsCount($form_id)
    {
        $sql = ("
        SELECT COUNT(*)
        FROM form_field
        WHERE form_id = :form_id
        ");

        return $this->di['db']->getCell($sql, array(':form_id' => $form_id));
    }


    public function getFormPairs()
    {
        $sql = "
            SELECT id, name
            FROM form
        ";

        return $this->di['db']->getAssoc($sql);
    }

    public function getField($fieldId)
    {
        $field = $this->di['db']->getExistingModelById('FormField', $fieldId, "Field was not found");

        $result = $this->di['db']->toArray($field);

        $required = array(
            'id' => 'Field was not found',
        );
        $this->di['validator']->checkRequiredParamsForArray($required, $result, null, 2575);

        if (substr($result["options"], 0, 1) == "{" || substr($result["options"], 0, 1) == "[") {
            $result['options'] = json_decode($result['options']);
        }
        return $result;

    }

    public function removeForm($form_id)
    {
        $sql = "DELETE
            FROM form_field
            WHERE  form_id = ?
        ";
        $this->di['db']->exec($sql, array($form_id));

        $sql2 = "DELETE
        FROM form
        WHERE id = ?";
        $this->di['db']->exec($sql2, array($form_id));

        $sql3 = "UPDATE product
        SET form_id = NULL
        WHERE form_id = ?
        ";
        $this->di['db']->exec($sql3, array($form_id));

        $sql4 = "UPDATE client_order
        SET form_id = NULL
        WHERE form_id = :form_id
        ";
        $this->di['db']->exec($sql4, array(':form_id' => $form_id));

        $this->di['logger']->info('Deleted custom form %s', $form_id);
        return true;
    }

    public function removeField($data)
    {
        $fieldModel = $this->di['db']->getExistingModelById('FormField', $data['id'], "Field was not found");
        $this->di['db']->trash($fieldModel);
        $this->di['logger']->info('Deleted custom field %s', $data['id']);
        return true;
    }


    public function formFieldNameExists($data)
    {
        $form_id = $data['form_id'];
        $field_name = $data['field_name'];
        $field_id = $data['field_id'];
        $sql = ("
        SELECT COUNT( * )
        FROM  `form_field`
        WHERE form_id = :form_id
        AND name =  :field_name
        AND id != :field_id
        ");

        $result = $this->di['db']->findOne('FormField', 'form_id = ? and name = ? and id != ?', array($form_id, $field_name, $field_id));
        return ($result) ? true : false;
    }

    public function getForms()
    {
        $sql = ("
        SELECT f.id, f.name, COUNT( p.id ) as product_count, COUNT( co.id ) as order_count
        FROM  `form` f
        LEFT JOIN product p ON (f.id = p.form_id)
        LEFT JOIN client_order co ON (f.id = co.form_id)
        GROUP BY f.id
        ");

        return $this->di['db']->getAll($sql);
    }

    public function duplicateForm($data)
    {

        $fields = $this->getFormFields($data['form_id']);
        $new_form_id = $this->addNewForm(array(
            "name" => $data['name']
        ));

        if (isset($fields) && is_array($fields)) {
            foreach ($fields as $field_data) {
                $field_data['form_id'] = $new_form_id;
                $this->addNewField($field_data);
            }
        }
        $this->di['logger']->info('Copied form with id %s to new form %s with id %s', $data['form_id'], $data['name'], $new_form_id);
        return $new_form_id;
    }

    public function updateFormSettings($data)
    {
        $show_title = isset($data['show_title'])? $data['show_title'] : "1";
        $type = $data['type'];

        $sql = "UPDATE `form`
                SET `name` =  :form_name
                WHERE id = :id";
        $this->di['db']->exec($sql, array(':form_name' => $data['form_name'], ':id' => $data['form_id']));

        $this->di['logger']->info('Updated form %s name to %s', $data['form_id'], $data['form_name']);

        $style = array(
            "type" => $type,
            "show_title" => $show_title
        );

        $sql2 = "UPDATE `form`
                SET `style` =  :type
                WHERE id = :id";
        $this->di['db']->exec($sql2, array(':type' => json_encode($style, JSON_FORCE_OBJECT), ':id' => $data['form_id']));
        $this->di['logger']->info('Updated form %s type to %s', $data['form_id'], $data['type']);
        return true;
    }


}
