<?php

if(!defined('INCLUDE_DIR')) die('!');

require_once(INCLUDE_DIR.'class.draft.php');
require_once(INCLUDE_DIR.'class.file.php');

class DraftAjaxAPI extends AjaxController {

    static function _createDraft($vars) {
        if (false === ($vars['body'] = self::_findDraftBody($_POST)))
            return JsonDataEncoder::encode(array(
                'error' => __("Draft body not found in request"),
                'code' => 422,
                ));

        if (!($draft = Draft::create($vars)) || !$draft->save())
            Http::response(500, 'Unable to create draft');

        header('Content-Type: application/json; charset=UTF-8');
        echo JsonDataEncoder::encode(array(
            'draft_id' => $draft->getId(),
        ));
    }

    static function _getDraft($draft) {
        if (!$draft || !$draft instanceof Draft)
            Http::response(205, "Draft not found. Create one first");

        $body = Format::viewableImages($draft->getBody());

        header('Content-Type: application/json; charset=UTF-8');
        echo JsonDataEncoder::encode(array(
            'body' => $body,
            'draft_id' => $draft->getId(),
        ));
    }

    static function _updateDraft($draft) {
        if (false === ($body = self::_findDraftBody($_POST)))
            return JsonDataEncoder::encode(array(
                'error' => array(
                    'message' => "Draft body not found in request",
                    'code' => 422,
                )
            ));

        if (!$draft->setBody($body))
            return Http::response(500, "Unable to update draft body");

        echo "{}";
    }

    static function _uploadInlineImage($draft) {
        global $cfg;

        if (!isset($_FILES['file']))
            Http::response(422, "File not included properly");

        # Fixup for expected multiple attachments
        $file = AttachmentFile::format($_FILES['file']);

        // Allow one file at a time.
        if (count($file) > 1)
            return Http::response(403,
                JsonDataEncoder::encode(array(
                    'error' => 'Send one file at a time',
                ))
            );

        # Allow for data-uri uploaded files
        $fp = fopen($file[0]['tmp_name'], 'rb');
        if (fread($fp, 5) == 'data:') {
            $data = 'data:';
            while ($block = fread($fp, 8192))
              $data .= $block;
            $file[0] = Format::parseRfc2397($data);
            list(,$ext) = explode('/', $file[0]['type'], 2);
            $file[0] += array(
                'name' => Misc::randCode(8).'.'.$ext,
                'size' => strlen($file[0]['data']),
            );
        }
        fclose($fp);

        // Check file type to ensure image
        $type = $file[0]['type'];
        if (!AttachmentFile::isInlineSafeImageType($file[0]['type']))
            return Http::response(403,
                JsonDataEncoder::encode(array(
                    'error' => 'File type is not allowed',
                ))
            );

        // Check if file is truly an image
        if (!FileUploadField::isValidFile($file[0]))
            return Http::response(403,
                JsonDataEncoder::encode(array(
                    'error' => 'File is not valid',
                ))
            );

        // Verify file size is acceptable
        if ($file[0]['size'] > $cfg->getMaxFileSize())
            return Http::response(403,
                JsonDataEncoder::encode(array(
                    'error' => 'File is too large',
                ))
            );

        // Paste uploads in Chrome will have a name of 'blob'
        if ($file[0]['name'] == 'blob')
            $file[0]['name'] = 'screenshot-'.Misc::randCode(4);

        $ids = $draft->attachments->upload($file);

        if (!$ids) {
            if ($file[0]['error']) {
                return Http::response(403,
                    JsonDataEncoder::encode(array(
                        'error' => $file[0]['error'],
                    ))
                );

            }
            else
                return Http::response(500, 'Unable to attach image');
        }

        $id = (is_array($ids)) ? $ids[0] : $ids;
        if (!($f = AttachmentFile::lookup($id)))
            return Http::response(500, 'Unable to attach image');

        header('Content-Type: application/json; charset=UTF-8');
        echo JsonDataEncoder::encode(array(
            Format::sanitize($f->getName()) => array(
            'content_id' => 'cid:'.$f->getKey(),
            'id' => $f->getKey(),
            // Return draft_id to connect the auto draft creation
            'draft_id' => $draft->getId(),
            'url' => $f->getDownloadUrl(
                ['type' => 'D', 'deposition' => 'inline']),
        )));
    }

    // Client interface for drafts =======================================
    function createDraftClient($namespace) {
        global $thisclient;

        if (!$thisclient && substr($namespace, -12) != substr(session_id(), -12))
            Http::response(403, "Valid session required");

        $vars = array(
            'namespace' => $namespace,
        );

        return self::_createDraft($vars);
    }

    function getDraftClient($namespace) {
        global $thisclient;

        if ($thisclient) {
            try {
                $draft = Draft::lookupByNamespaceAndStaff($namespace,
                    $thisclient->getId());
            }
            catch (DoesNotExist $e) {
                Http::response(205, "Draft not found. Create one first");
            }
        }
        else {
            if (substr($namespace, -12) != substr(session_id(), -12))
                Http::response(404, "Draft not found");
            try {
                $draft = Draft::lookupByNamespaceAndStaff($namespace, 0);
            }
            catch (DoesNotExist $e) {
                Http::response(205, "Draft not found. Create one first");
            }
        }
        return self::_getDraft($draft);
    }

    function updateDraftClient($id) {
        global $thisclient;

        if (!($draft = Draft::lookup($id)))
            Http::response(205, "Draft not found. Create one first");
        // Check the owning client-id (for logged-in users), and the
        // session_id() for others
        elseif ($thisclient) {
            if ($draft->getStaffId() != $thisclient->getId())
                Http::response(404, "Draft not found");
        }
        else {
            if (substr(session_id(), -12) != substr($draft->getNamespace(), -12))
                Http::response(404, "Draft not found");
        }

        return self::_updateDraft($draft);
    }

    function deleteDraftClient($id) {
        global $thisclient;

        if (!($draft = Draft::lookup($id)))
            Http::response(205, "Draft not found. Create one first");
        elseif ($thisclient) {
            if ($draft->getStaffId() != $thisclient->getId())
                Http::response(404, "Draft not found");
        }
        else {
            if (substr(session_id(), -12) != substr($draft->getNamespace(), -12))
                Http::response(404, "Draft not found");
        }

        $draft->delete();
    }

    function uploadInlineImageClient($id) {
        global $thisclient;

        if (!($draft = Draft::lookup($id)))
            Http::response(205, "Draft not found. Create one first");
        elseif ($thisclient) {
            if ($draft->getStaffId() != $thisclient->getId())
                Http::response(404, "Draft not found");
        }
        else {
            if (substr(session_id(), -12) != substr($draft->getNamespace(), -12))
                Http::response(404, "Draft not found");
        }

        return self::_uploadInlineImage($draft);
    }

    function uploadInlineImageEarlyClient($namespace) {
        global $thisclient;

        if (!$thisclient && substr($namespace, -12) != substr(session_id(), -12))
            Http::response(403, "Valid session required");

        $draft = Draft::create(array(
            'namespace' => $namespace,
            'body' => ''
        ));
        if (!$draft->save())
            Http::response(500, 'Unable to create draft');

        return $this->uploadInlineImageClient($draft->getId());
    }

    // Staff interface for drafts ========================================
    function createDraft($namespace) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for draft creation");

        $vars = array(
            'namespace' => $namespace,
        );

        return self::_createDraft($vars);
    }

    function getDraft($namespace) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for draft creation");
        try {
            $draft = Draft::lookupByNamespaceAndStaff($namespace,
                $thisstaff->getId());
        }
        catch (DoesNotExist $e) {
            Http::response(205, "Draft not found. Create one first");
        }

        return self::_getDraft($draft);
    }

    function updateDraft($id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for image upload");
        elseif (!($draft = Draft::lookup($id)))
            Http::response(205, "Draft not found. Create one first");
        elseif ($draft->getStaffId() != $thisstaff->getId())
            Http::response(404, "Draft not found");

        return self::_updateDraft($draft);
    }

    function uploadInlineImage($draft_id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for image upload");
        elseif (!($draft = Draft::lookup($draft_id)))
            Http::response(205, "Draft not found. Create one first");
        elseif ($draft->getStaffId() != $thisstaff->getId())
            Http::response(404, "Draft not found");

        return self::_uploadInlineImage($draft);
    }

    function uploadInlineImageEarly($namespace) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for image upload");

        $draft = Draft::create(array(
            'namespace' => $namespace,
            'body' => ''
        ));
        if (!$draft->save())
            Http::response(500, 'Unable to create draft');

        return $this->uploadInlineImage($draft->getId());
    }

    function deleteDraft($id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for draft edits");
        elseif (!($draft = Draft::lookup($id)))
            Http::response(205, "Draft not found. Create one first");
        elseif ($draft->getStaffId() != $thisstaff->getId())
            Http::response(404, "Draft not found");

        $draft->delete();
    }

    function getFileList() {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required for file queries");

        $search = Q::any([
            Q::all([
                'attachments__type__in' => array('C', 'F', 'T', 'P'),
                'attachments__inline' => 1,
            ]),
            'ft' => 'L',
        ]);

        if (isset($_GET['threadId']) && is_numeric($_GET['threadId'])
            && ($thread = Thread::lookup($_GET['threadId']))
            && ($object = $thread->getObject())
            && ($thisstaff->canAccess($object))
        ) {
            $search->add(Q::all([
                'attachments__thread_entry__thread_id' => $_GET['threadId'],
                'attachments__inline' => 1,
            ]));
        }

        $images = AttachmentFile::objects()->filter([
                $search,
                'type__startswith' => 'image/',
            ])->distinct('id');

        $files = array();
        foreach ($images as $f) {
            if (!$f->isInlineSafeImage())
                continue;

            $url = $f->getDownloadUrl();
            $files[] = array(
                // Don't send special sizing for thread items 'cause they
                // should be cached already by the client
                'thumb' => $url.($f->type != 'H' ? '&s=128' : ''),
                'url' => $url,
                'title' => $f->getName(),
            );
        }
        header('Content-Type: application/json; charset=UTF-8');
        echo JsonDataEncoder::encode($files);
    }

    static function _findDraftBody($vars) {
        if (isset($vars['name'])) {
            $parts = array();
            // Support nested `name`, like trans[lang]
            if (preg_match('`(\w+)(?:\[(\w+)\])?(?:\[(\w+)\])?`', $_POST['name'], $parts)) {
                array_shift($parts);
                $focus = $vars;
                foreach ($parts as $p)
                    $focus = $focus[$p];
                return $focus;
            }
        }

        // Get ThreadEntry field name.
        $tform = TicketForm::objects()->one()->getForm();
        $tfield = $tform->getField('message')->getFormName();
        // Get Task Description field name.
        $aform = TaskForm::objects()->one()->getForm();
        $afield = $aform->getField('description')->getFormName();
        $field_list = array('response', 'note', 'answer', 'body',
             $tfield, 'issue', $afield);
        foreach ($field_list as $field) {
            if (isset($vars[$field])) {
                return $vars[$field];
            }
        }

        return false;
    }

}
?>
