<?php

namespace Velis\Bpm\Ticket\Post;

use Velis\Model\BaseModel;
use Velis\Bpm\Ticket\Post;
use Velis\Bpm\Ticket\Post\Checklist\Item;
use Velis\Filter;
use SimpleXMLElement;
use Exception;

/**
 * Checklist
 *
 * @author Robert Jamróz <robert.jamroz@velis.pl>
 * @author Olek Procki <olo@velis.pl>
 */
class Checklist extends BaseModel
{
    const TEXTILE_TAG_START = ":chl ";
    const TEXTILE_TAG_END   = ":/chl";


    /**
     * Related ticket post
     * @var \Velis\Bpm\Ticket\Post
     */
    protected $_post;


    /**
     * XML source
     * @var \SimpleXmlElement
     */
    protected $_xml;



    /**
     * Constructor
     *
     * @param \Velis\Bpm\Ticket\Post $post
     * @param bool $extract
     */
    public function __construct(Post $post, $extract = true)
    {
        $this->_post = $post;

        $pattern = '~' . self::TEXTILE_TAG_START . '(.*)' . self::TEXTILE_TAG_END . '~ms';

        if (preg_match_all($pattern, $this->_post['content'], $matches)) {
            $checklistContents = $matches[1][0];

            try {
                $this->_xml = @new SimpleXMLElement(
                    preg_replace(
                        '~<del>~',
                        '',
                        preg_replace(
                            array(
                                '~<li>(\s+)?<del>~',
                                '~</del>~',
                                '~</?strong>~',
                                '~</?em>~',
                                '~</?ins>~',
                                '~</?code>~',
                                '~<a.+href="([^"]+)".+>([^<]+)<\/a>~'
                            ),
                            array(
                                '<li closed="1">',
                                '',
                                '*',
                                '_',
                                '+',
                                '@',
                                '"$2":$1'
                            ),
                            strip_tags(
                                Filter::filterTextile($checklistContents, false, '', true),
                                '<ol><li><del><strong><em><ins><code><a>'
                            )
                        )
                    )
                );

                if ($extract) {
                    $this->_post['content'] = str_replace(
                        array(
                            $checklistContents,
                            self::TEXTILE_TAG_START,
                            self::TEXTILE_TAG_END
                        ),
                        '',
                        $this->_post['content']
                    );
                }
            } catch (Exception $e) {
            }
        }
    }


    /**
     * Returns true if checklist has any elements
     * @return bool
     */
    public function hasItems()
    {
        return $this->_xml instanceof SimpleXMLElement && $this->_xml->children();
    }


    /**
     * Returns related ticket post
     * @return \Velis\Bpm\Ticket\Post
     */
    public function getPost()
    {
        if (!isset($this->_post)) {
            $this->_post = Post::instance($this['ticket_post_id']);
        }
        return $this->_post;
    }



    /**
     * Creates checklist
     *
     * @param \SimpleXmlElement $node
     * @param \Velis\Bpm\Ticket\Post\Checklist\Item $parent
     *
     * @return \Velis\Bpm\Ticket\Post\Checklist
     */
    public function create(SimpleXmlElement $node = null, $parent = null)
    {
        if ($node == null) {
            $source = $this->_xml;
        } else {
            $source = $node;
        }

        if ($source instanceof SimpleXMLElement && $source->children()) {
            foreach ($source->children() as $elem) {
                if ($elem->getName() == 'li') {
                    $isClosedItem = false;
                    foreach ($elem->attributes() as $attr => $value) {
                        if ($attr == 'closed') {
                            $isClosedItem = true;
                            break;
                        }
                    }
                    $text = trim((string)$elem);

                    $item = new Item(
                        array(
                            'ticket_post_id'                  => $this->_post->id(),
                            'parent_ticket_post_checklist_id' => $parent ? $parent->id() : null,
                            'name'                            => $text,
                            'is_closed'                       => $isClosedItem ? 1 : 0
                        )
                    );

                    $item->add(true);
                }
                if ($elem->children()) {
                    $this->create($elem, $item ?: $parent);
                }
            }
        }

        return $this;
    }


    /**
     * Updates checklist items
     * @return \Velis\Bpm\Ticket\Post\Checklist
     */
    public function update()
    {
        $commit = self::$_db->startTrans();

        try {
            self::$_db->execDML(
                'DELETE FROM app.ticket_post_checklist_tab WHERE ticket_post_id=:ticket_post_id',
                array (
                    'ticket_post_id' => $this->_post->id()
                )
            );

            $this->create();

            if ($commit) {
                self::$_db->commit();
            }
        } catch (Exception $e) {
            self::$_db->rollback();
        }

        return $this;
    }


    /**
     * Check if String contain checklist
     * @param String $string
     * @return int
     */
    public static function containChecklist($string)
    {
        $pattern = '~' . self::TEXTILE_TAG_START . '(.*)' . self::TEXTILE_TAG_END . '~ms';

        return preg_match_all($pattern, $string, $matches);
    }
}
