<?php

class ACMS_Validator_Category extends ACMS_Validator
{
    function double($ccd, $arg)
    {
        if ( empty($ccd) ) return true;

        $scope  = isset($arg[0]) ? $arg[0] : 'local';
        $cid    = isset($arg[1]) ? $arg[1] : null;

        $DB = DB::singleton(dsn());

        //------
        // blog
        if ( !ACMS_RAM::blogCode(BID) ) {
            $domain = ACMS_RAM::blogDomain(BID);
            $SQL    = SQL::newSelect('blog');
            $SQL->setSelect('blog_id');
            $SQL->addWhereOpr('blog_domain', $domain);
            $SQL->addWhereOpr('blog_code', $ccd);
            $SQL->setSelect(1);
            if ( $DB->query($SQL->get(dsn()), 'one') ) return false;
        }

        //---------
        // sibling
        $SQL    = SQL::newSelect('category');
        $SQL->setSelect('category_id');
        $SQL->addWhereOpr('category_code', $ccd);
        $SQL->addWhereOpr('category_blog_id', BID);
        if ( !!($cid = intval($cid)) ) {
            $SQL->addWhereOpr('category_id', $cid, '<>');
        }
        if ( !!$DB->query($SQL->get(dsn()), 'one') ) {
            return false;
        }

        //----------
        // ancestor
        $SQL    = SQL::newSelect('category');
        $SQL->addLeftJoin('blog', 'blog_id', 'category_blog_id');
        ACMS_Filter::blogTree($SQL, BID, 'ancestor');
        $SQL->addSelect('category_id');
        $SQL->addWhereOpr('category_code', $ccd);
        $SQL->addWhereOpr('category_scope', 'global');

        if ( !!$DB->query($SQL->get(dsn()), 'one') ) {
            return false;
        }

        if ( 'local' == $scope ) {
            return true;
        }

        //------------
        // descendant
        $SQL    = SQL::newSelect('category');
        $SQL->addLeftJoin('blog', 'blog_id', 'category_blog_id');
        ACMS_Filter::blogTree($SQL, BID, 'descendant');
        $SQL->addSelect('category_id');
        $SQL->addWhereOpr('category_code', $ccd);
        return !$DB->query($SQL->get(dsn()), 'one');
    }

    function _double($val, $cid=null)
    {
        if ( empty($val) ) return true;
        $DB     = DB::singleton(dsn());

        //------
        // blog
        if ( !ACMS_RAM::blogCode(BID) ) {
            $domain = ACMS_RAM::blogDomain(BID);
            $SQL    = SQL::newSelect('blog');
            $SQL->setSelect('blog_id');
            $SQL->addWhereOpr('blog_domain', $domain);
            $SQL->addWhereOpr('blog_code', $val);
            $SQL->setSelect(1);
            if ( $DB->query($SQL->get(dsn()), 'one') ) return false;
        }

        //----------
        // category
        $SQL    = SQL::newSelect('category');
        $SQL->setSelect('category_id');
        $SQL->addWhereOpr('category_code', $val);
        $SQL->addWhereOpr('category_blog_id', BID);
        if ( $cid = idval($cid) ) {
            $SQL->addWhereOpr('category_id', $cid, '<>');
        }

        return !$DB->query($SQL->get(dsn()), 'one');
    }

    function status($val)
    {
        if ( empty($val) ) return true;
        if ( !CID ) return true;
        if ( 'open' <> $val ) return true;

        $DB     = DB::singleton(dsn());
        $SQL    = SQL::newSelect('category');
        $SQL->setSelect('category_id');
        $SQL->addWhereOpr('category_blog_id', BID);
        $l  = ACMS_RAM::categoryLeft(CID);
        $r  = ACMS_RAM::categoryRight(CID);
        $SQL->addWhereOpr('category_left', $l, '<');
        $SQL->addWhereOpr('category_right', $r, '>');
        $SQL->addWhereOpr('category_status', 'close');
        $SQL->setLimit(1);

        return !$DB->query($SQL->get(dsn()), 'one');
    }
}

class ACMS_POST_Category extends ACMS_POST
{
    protected $workflowData = false;

    function changeParentCategory($cid, $toPid)
    {
        if ( !$cid = idval($cid) ) return false;
        if ( $toPid == $cid ) return false;
        if ( BID <> ACMS_RAM::categoryBlog($cid) ) return false;

        $DB = DB::singleton(dsn());

        //-----------------------------
        // from:left, right, pid, sort
        $SQL    = SQL::newSelect('category');
        $SQL->addSelect('category_left');
        $SQL->addSelect('category_right');
        $SQL->addSelect('category_parent');
        $SQL->addSelect('category_sort');
        $SQL->addWhereOpr('category_id', $cid);
        $SQL->addWhereOpr('category_blog_id', BID);
        if ( !$row = $DB->query($SQL->get(dsn()), 'row') ) die();
        $fromLeft   = intval($row['category_left']);
        $fromRight  = intval($row['category_right']);
        $fromPid    = intval($row['category_parent']);
        $fromSort   = intval($row['category_sort']);

        //-------------
        // same parent
        if ( $toPid == $fromPid ) return false;

        //------------------------
        // to: left, right, sort
        if ( !empty($toPid) ) {
            $SQL    = SQL::newSelect('category');
            $SQL->addSelect('category_left');
            $SQL->addSelect('category_right');
            $SQL->addWhereOpr('category_id', $toPid);
            $SQL->addWhereOpr('category_blog_id', BID);
            if ( !$row = $DB->query($SQL->get(dsn()), 'row') ) die();
            $toLeft     = $row['category_left'];
            $toRight    = $row['category_right'];

            if ( $toLeft > $fromLeft and $toRight < $fromRight ) return false; 

            //-------
            // toSort
            $SQL    = SQL::newSelect('category');
            $SQL->setSelect('category_sort');
            $SQL->addWhereOpr('category_parent', $toPid);
            $SQL->addWhereOpr('category_blog_id', BID);
            $SQL->setOrder('category_sort', 'DESC');
            $SQL->setLimit(1);
            $toSort = intval($DB->query($SQL->get(dsn()), 'one')) + 1;

        } else {

            $SQL    = SQL::newSelect('category');
            $SQL->addSelect('category_right');
            $SQL->addSelect('category_sort');
            $SQL->addWhereOpr('category_blog_id', BID);
            $SQL->setOrder('category_right', 'DESC');
            $SQL->setLimit(1);
            if ( !$row = $DB->query($SQL->get(dsn()), 'row') ) die();
            $toLeft     = intval($row['category_right']);
            $toRight    = $toLeft   + 1;
            $toSort     = intval($row['category_sort']) + 1;;
        }

        //-----
        // gap
        $gap    = ($fromRight - $fromLeft) + 1;

        //-------
        // align
        $SQL    = SQL::newUpdate('category');
        $SQL->addWhereOpr('category_blog_id', BID);
        if ( $fromRight > $toRight ) {
            //-------
            // upper
            $delta  = $fromLeft - $toRight;

            $Case   = SQL::newCase();
            $Case->add(
                SQL::newOprBw('category_left', $fromLeft, $fromRight)
                , SQL::newOpr('category_left', $delta, '-')
            );
            $Where  = SQL::newWhere();
            $Where->addWhereOpr('category_left', $toRight, '>=');
            $Where->addWhereOpr('category_left', $fromLeft, '<');
            $Case->add($Where, SQL::newOpr('category_left', $gap, '+'));
            $Case->setElse(SQL::newField('category_left'));
            $SQL->addUpdate('category_left', $Case);

            $Case   = SQL::newCase();
            $Case->add(
                SQL::newOprBw('category_right', $fromLeft, $fromRight)
                , SQL::newOpr('category_right', $delta, '-')
            );
            $Where  = SQL::newWhere();
            $Where->addWhereOpr('category_right', $toRight, '>=');
            $Where->addWhereOpr('category_right', $fromLeft, '<');
            $Case->add($Where, SQL::newOpr('category_right', $gap, '+'));
            $Case->setElse(SQL::newField('category_right'));
            $SQL->addUpdate('category_right', $Case);

        } else {
            //------
            // lower
            $delta  = $toRight - $fromRight - 1;

            $Case   = SQL::newCase();
            $Case->add(
                SQL::newOprBw('category_left', $fromLeft, $fromRight)
                , SQL::newOpr('category_left', $delta, '+')
            );
            $Where  = SQL::newWhere();
            $Where->addWhereOpr('category_left', $fromRight, '>');
            $Where->addWhereOpr('category_left', $toRight, '<');
            $Case->add($Where, SQL::newOpr('category_left', $gap, '-'));
            $Case->setElse(SQL::newField('category_left'));
            $SQL->addUpdate('category_left', $Case);

            $Case   = SQL::newCase();
            $Case->add(
                SQL::newOprBw('category_right', $fromLeft, $fromRight)
                , SQL::newOpr('category_right', $delta, '+')
            );
            $Where  = SQL::newWhere();
            $Where->addWhereOpr('category_right', $fromRight, '>');
            $Where->addWhereOpr('category_right', $toRight, '<');
            $Case->add($Where, SQL::newOpr('category_right', $gap, '-'));
            $Case->setElse(SQL::newField('category_right'));
            $SQL->addUpdate('category_right', $Case);

        }
        $DB->query($SQL->get(dsn()), 'exec');

        //--------
        // sort
        $SQL    = SQL::newUpdate('category');
        $SQL->setUpdate('category_sort', SQL::newOpr('category_sort', 1, '-'));
        $SQL->addWhereOpr('category_sort', $fromSort, '>');
        $SQL->addWhereOpr('category_parent', $fromPid);
        $SQL->addWhereOpr('category_blog_id', BID);
        $DB->query($SQL->get(dsn()), 'exec');

        //--------
        // update
        $SQL    = SQL::newUpdate('category');
        $SQL->addUpdate('category_parent', $toPid);
        $SQL->addUpdate('category_sort', $toSort);
        $SQL->addWhereOpr('category_id', $cid);
        $SQL->addWhereOpr('category_blog_id', BID);
        $DB->query($SQL->get(dsn()), 'exec');

        ACMS_RAM::category($cid, null);
    }

}
