<?php
/**
 * Created by PhpStorm.
 * User: cpueblo
 * Date: 2016. 8. 30.
 * Time: 오후 4:56
 */

namespace platyFramework;

/**
 * Class ptyItemsModel
 * @package platyFramework
 *
 *
 * example)
 */
/*
<?php
namespace platyFramework;

class yourItemsModel extends ptyItemsModel
{
    public $_tableName = "t_your";
    public $_itemModel = "platyFramework\\ptyItemModel";

    function __construct()
    {
        parent::__construct();
    }

    function _migrate()
    {
        if (!$this->db->sql_result("SHOW TABLES LIKE '{$this->_tableName}'")) {
            $this->db->sql_query("
                CREATE TABLE IF NOT EXISTS `{$this->_tableName}` (
                `id` int(11) NOT NULL AUTO_INCREMENT,
                `enabled` tinyint(1) NOT NULL DEFAULT '1',
                `regDateTime` datetime NULL,
                `ip` varchar(64) NULL,
                `userId` varchar(64) NULL,

                `something` varchar(64) null comment '',
                PRIMARY KEY (`id`)

            ) ENGINE=InnoDB DEFAULT CHARSET=" . PLATYFRAMEWORK_DB_CHARSET . " COLLATE=" . PLATYFRAMEWORK_DB_COLLATE . " AUTO_INCREMENT=1;
            ");
        }

        if (!$this->db->sql_result("SHOW COLUMNS FROM `{$this->_tableName}` LIKE 'hello'")) {
            $this->db->sql_query("ALTER TABLE `{$this->_tableName}` ADD `hello` varchar(64) null default '' comment '';");
        }
    }
}
?>
*/

/**
 * Class ptyItemsModel
 * @package platyFramework
 *
 * 필수 db 항목
 *
 * `id` int(11) NOT NULL AUTO_INCREMENT,
 * `descId` int(11) NULL DEFAULT 0,
 * `enabled` tinyint(1) NOT NULL DEFAULT '1',
 * `regDateTime` datetime NULL,
 * `ip` varchar(64) NULL DEFAULT '',
 * `serviceUserId` varchar(64) NULL DEFAULT '',
 * `userId` varchar(64) null default '',
 *
 */
class ptyItemsModel extends model
{
    public $_tableName = "";
    public $_itemModel = "platyFramework\ptyItemModel";

    /** @var int 페이징 - 페이지당 표시할 개수 */
    public $_itemsPerPage = 0;
    public $db2;
    public $enableDescId = TRUE;
    public $enableConveringIndex = false;
    public $enableUploadFileMatchColumn = true;
    protected $pageIndex = 0;
    protected $enabled = 1;
    protected $_pageName = "page";
    /** @var int 페이징 - 섹션당 표시할 개수 */
    private $_pagePerSection = 10;
    /** @var int 총 개수 */
    private $_totalCount;

    private $_splitTableId = "";

    public $_useDescId = false;
    public $_useEnabled = true;

    public $_use_col_ip = true;
    public $_use_col_userId = true;
    public $_use_col_serviceUserId = true;
    public $_use_col_regDateTime = true;
    public $_use_col_descId = true;
    public $_use_col_enabled = true;

    /**
     * @var bool 커버링 인덱스 사용 여부
     */
    public $_useCoveringIndex = false;

    /**
     * @var bool COUNT 시에도 커버링 인덱스 사용 여부
     */
    public $_useCoveringIndexAtCount = false;

    /**
     *
     * @var bool table Schema 를 이용하여 count 를 계산합니다
     */
    public $_useTableSchemaAtCount = false;


    public $_primaryColumnName = "id";

    function __construct(?string $tableName = "", ?string $itemModelClassName = "")
    {
        parent::__construct();

        if ($tableName != "") $this->_tableName = $tableName;
        if ($itemModelClassName != "") $this->_itemModel = $itemModelClassName;

        if ($this->_tableName == "") {
            ptyShowCallstack();
            ptyError("this->tableName 을 지정해야 합니다");
        }
        if ($this->_itemModel == "") {
            ptyShowCallstack();
            // ptyDebugBackTrace();
            ptyError("this->itemModelClassName 을 지정해야 합니다");
        }

        $this->db = clone $this->db;
        $this->db2 = clone $this->db;

        if ($GLOBALS['migrated_' . get_class($this)] != "1") {
            $GLOBALS['migrated_' . get_class($this)] = 1;
            $this->_migrate();
        }
        $this->clear();
    }

    function _migrate()
    {
    }

    public function clear()
    {
        $this->db->clear();
        $this->db2->clear();
        $this->db->initSelect();
        $this->db->addFrom($this->_tableName);
        // ptyDebug("tableName = ".$this->tableName, "63");
        // ptyDebug($this->db);
        /*
        $this->enabled = $enabled;
        if ($enabled) $this->db->addWhereEqual("{$this->tableName}.enabled", "1");
        */

        return $this;
    }

    /**
     * List 생성
     * @param string $tableName
     * @param string $tableItemModel
     *
     * @return static
     */
    public static function build(?string $tableName = "", ?string $itemModelClassName = "")
        // [cpueblo] 2021-02-02
        // public static function build($tableName = "", $itemModelClassName = "platyFramework\ptyItemModel")
    {
        $list = new static (tableName: $tableName, itemModelClassName: $itemModelClassName);

        // [cpueblo] 2021-02-02
        // $list = new static ($tableName, $itemModelClassName);
        // $list->_tableName = $tableName;
        return $list;
    }

    /**
     *
     * @param ptyArrayItemModel $data
     * @return ptyItemModel mixed
     */
    public static function buildItem($data = array())
    {
        $list = new static ();
        $itemClassName = $list->_itemModel;
        $item = new $itemClassName($list->_tableName, $data->_item);
        return $item;
    }

    public static function buildWithItems($items)
    {
        $ret = array();
        foreach ($items as $k => $v) {
            $ret[] = static::buildItem($v);
        }

        return $ret;
    }


    /**
     * items 에서 특정 컬럼만을 추출하여 배열로 리턴합니다
     *
     * @param $items
     * @param null $fields
     * @return array
     */
    public static function convertRawItems($items, $fields = null)
    {
        foreach ($items as $item) {

            if (isset($fields) && is_array($fields)) {
                $newItem = array();
                foreach ($fields as $field => $v) {
                    $newItem[$v] = $item->_item[$v];
                }
                $newItems[] = $newItem;

            } else {
                $newItems[] = $item->_item;
            }
        }

        return $newItems;
    }

    public static function convertRawItems2($items, $fields = null)
    {
        foreach ($items as $item) {

            if (isset($fields) && is_array($fields)) {
                $newItem = array();
                foreach ($fields as $field => $v) {
                    $newItem[] = $item->_item[$v];
                }
                $newItems[] = $newItem;

            } else {
                $newItems[] = $item->_item;
            }
        }

        return $newItems;
    }

    /**
     * 디비에서 특정 컬럼만을 추출합니다
     *
     * ex) $data['titles'] = someItemsModel::convertRawColumn(someItemsModel::build()->getItemsBy(["category" => "카테고리1"]), "title");
     *
     */
    public static function convertRawColumn($items, $fieldName)
    {
        foreach ($items as $item) {
            $newItems[] = $item->_item[$fieldName];
        }

        return $newItems;
    }

    /**
     * [id] => $fieldName 의 value 를 가진 값을 리턴합니다.
     * ex) $data['items'] = ptyItemsModel::convertRawColumnById(ptyItemsModel::build()->getItemsBy(["category" => "분류1"]),"title");
     * output>
     * Array(
     * [12] => title의 값1
     * [13] => title의 값1
     * );
     * @param $items
     * @param $fieldName
     * @return mixed
     */
    public static function convertRawColumnById($items, $fieldName)
    {
        foreach ($items as $item) {
            $newItems[$item->id] = $item->_item[$fieldName];
        }

        return $newItems;
    }


    public static function getSelectColumn($items, $fieldName)
    {
        foreach ($items as $item) {
            $newItems[$item->$fieldName] = $item->_item['id'];
        }

        return $newItems;
    }


    /**
     * @param null $data
     * @return ptyItemModel $item
     */
    public function _buildItem($data = NULL)
    {
        $itemClassName = $this->_itemModel;
        $item = new $itemClassName($this->_tableName, $data);

        return $item;
    }

    function setEnabled($enabled = TRUE)
    {
        $this->enabled = $enabled;
        if ($enabled == TRUE)
            $this->db->addWhereEqual("{$this->_tableName}.enabled", "1");
        else if ($enabled == FALSE)
            $this->db->addWhereEqual("{$this->_tableName}.enabled", "0");


        return $this;
    }

    public function getPaging()
    {
        $page = (int)$this->request->request[$this->_pageName];
        if ($page == 0)
            $page = 1;

        $totalPageCount = ceil($this->_totalCount / $this->_itemsPerPage);
        if ($totalPageCount == 0) $totalPageCount = 1;
        $currentSection = ceil($page / $this->_pagePerSection);
        $totalSectionCount = ceil($totalPageCount / $this->_pagePerSection);
        $firstPage = ($currentSection * $this->_pagePerSection) - ($this->_pagePerSection - 1);
        if ($totalSectionCount > 0) {
            if ($currentSection == $totalSectionCount) {
                $lastPage = $totalPageCount;
            } else {
                $lastPage = $currentSection * $this->_pagePerSection;
            }
        }

        $prevPage = (($currentSection - 1) * $this->_pagePerSection);
        $nextPage = (($currentSection + 1) * $this->_pagePerSection) - ($this->_pagePerSection - 1);
//        ptyDebug($totalPageCount, "totalPageCount");
//        ptyDebug($prevPage, "prevPage");
//        ptyDebug($currentSection, "currentSection");
//        ptyDebug($totalSectionCount, "totalSectionCount");
//        ptyDebug($lastPage, "lastPage");

        // 처음으로
        $out = "";
        if ($page != 1) {
            $url = ptyRebuildParams("page=1");
            $out .= "<li class='first'><a href='{$url}'>&lt;&lt;</a></li>";
        }

        // 이전 섹션
        if ($currentSection != 1) {
            $url = ptyRebuildParams("page={$prevPage}");
            $out .= "<li class='prev'><a href='{$url}'>&lt;</a></li>";
        }

        for ($i = $firstPage; $i <= $lastPage; $i++) {
            $url = ptyRebuildParams("page={$i}");
            if ($i == $page) {
                $out .= "<li class='active'><a href='{$url}'>{$i}</a></li>";
            } else {
                $out .= "<li><a href='{$url}'>{$i}</a></li>";
            }
        }

        // 다음 섹션
        if ($currentSection != $totalSectionCount) {
            $url = ptyRebuildParams("page={$nextPage}");
            $out .= "<li class='next'><a href='{$url}'>&gt;</a></li>";
        }

        // 마지막으로
        if ($page != $totalPageCount) {
            $url = ptyRebuildParams("page={$totalPageCount}");
            $out .= "<li class='last'><a href='{$url}'>&gt;&gt;</a></li>";
        }

        return $out;
    }

    public function getPagingx($maxPagesToShow = 10)
    {
        if ($this->_itemsPerPage == 0) return "";

        $page = (int)$this->request->request[$this->_pageName];
        if ($page == 0)
            $page = 1;

        $p = new Paginator($this->_totalCount, $this->_itemsPerPage, $page, '');
        $p->setMaxPagesToShow($maxPagesToShow);

        $first = ptyRebuildUrl(array($this->_pageName => 1));
        $prev = ptyRebuildUrl(array($this->_pageName => $p->getPrevPage() ? $p->getPrevPage() : 1));
        $next = ptyRebuildUrl(array($this->_pageName => $p->getNextPage() ? $p->getNextPage() : $p->getNumPages()));
        $last = ptyRebuildUrl(array($this->_pageName => $p->getNumPages()));

        $out = "<ul class='pull-right pagination pagination-sm no-margin clearfix'>";
        $out .= "<li class='prev'><a href='$first' class='first'>처음</a></li>";
        $out .= "<li class='prev'><a href='$prev' class='prev'>이전</a></li>";

        foreach ($p->getPages() as $item) {

            if ($item['num'] == "...") {
                $url = "";
            } else {
                $url = ptyRebuildUrl(array($this->_pageName => $item['num']));

                if ($item['isCurrent'])
                    $out .= "<li class='active'><a href='$url'>" . $item['num'] . "</a></li>";
                else
                    $out .= "<li><a href='$url'>" . $item['num'] . "</a></li>";
            }
        }
        $out .= "<li class='next'><a href='$next' class='next'>다음</a></li>";
        $out .= "<li class='prev'><a href='$last' class='last'>마지막</a></li>";
        $out .= "</ul>";

        return $out;
    }

    public function getPaging2($maxPagesToShow = 10)
    {
        if ($this->_itemsPerPage == 0) return "";

        $page = (int)$this->request->request[$this->_pageName];
        if ($page == 0)
            $page = 1;

        $p = new Paginator($this->_totalCount, $this->_itemsPerPage, $page, '');
        $p->setMaxPagesToShow($maxPagesToShow);

        $first = ptyRebuildUrl(array($this->_pageName => 1));
        $prev = ptyRebuildUrl(array($this->_pageName => $p->getPrevPage() ? $p->getPrevPage() : 1));
        $next = ptyRebuildUrl(array($this->_pageName => $p->getNextPage() ? $p->getNextPage() : $p->getNumPages()));
        $last = ptyRebuildUrl(array($this->_pageName => $p->getNumPages()));

        $out = "<ul class='text-center pagination clearfix' style='margin: 0px;'>";
        $out .= "<li class='prev'><a href='$prev' class='prev'>이전</a></li>";
        foreach ($p->getPages() as $item) {

            if ($item['num'] == "...") {
                $out .= "<li class=disable><span>...</span></a></li>";
            } else {
                $url = ptyRebuildUrl(array($this->_pageName => $item['num']));

                if ($item['isCurrent'])
                    $out .= "<li class='active'><a href='$url'>" . $item[num] . "</a></li>";
                else
                    $out .= "<li><a href='$url'>" . $item[num] . "</a></li>";
            }
        }
        $out .= "<li class='next'><a href='$next' class='next'>다음</a></li>";
        $out .= "</ul>";

        return $out;
    }

    public function getPaging3($maxPagesToShow = 5, $pagingExtendClass = "")
    {
        if ($this->_itemsPerPage == 0) return "";

        $page = (int)$this->request->request[$this->_pageName];
        if ($page == 0)
            $page = 1;

        $p = new Paginator($this->_totalCount, $this->_itemsPerPage, $page, '');

        $p->setMaxPagesToShow($maxPagesToShow);

        $first = ptyRebuildUrl(array($this->_pageName => 1));
        $prev = ptyRebuildUrl(array($this->_pageName => $p->getPrevPage() ? $p->getPrevPage() : 1));
        $next = ptyRebuildUrl(array($this->_pageName => $p->getNextPage() ? $p->getNextPage() : $p->getNumPages()));
        $last = ptyRebuildUrl(array($this->_pageName => $p->getNumPages()));

        $out = <<<END
<div class="paging $pagingExtendClass">
	<a href="$prev" class="prev">이전</a>
END;
        foreach ($p->getPages() as $item) {
            if ($item['num'] == "...") {
                $out .= "<a href='#'>{$item['num']}</a>";
                continue;
            }

            $on = "";
            $url = ptyRebuildUrl(array($this->_pageName => $item['num']));
            if ($item['isCurrent'])
                $on = " class='on'";
            $out .= "<a href='$url' $on>{$item['num']}</a>";
        }

        $out .= <<<END
	<a href="$next" class="next">다음</a>
</div>
END;

        return $out;

        $out = "<ul class='text-center pagination clearfix' style='margin: 0px;'>";
        $out .= "<li class='prev'><a href='$prev' class='prev'>이전</a></li>";
        foreach ($p->getPages() as $item) {

            if ($item['num'] == "...") {
                $out .= "<li class=disable><span>...</span></a></li>";
            } else {
                $url = ptyRebuildUrl(array($this->_pageName => $item['num']));

                if ($item['isCurrent'])
                    $out .= "<li class='active'><a href='$url'>" . $item[num] . "</a></li>";
                else
                    $out .= "<li><a href='$url'>" . $item[num] . "</a></li>";
            }
        }
        $out .= "<li class='next'><a href='$next' class='next'>다음</a></li>";
        $out .= "</ul>";

        return $out;
    }

    public function getPagingLi3($maxPagesToShow = 5)
    {
        if ($this->_itemsPerPage == 0) return "";

        $page = (int)$this->request->request[$this->_pageName];
        if ($page == 0)
            $page = 1;

        $p = new Paginator($this->_totalCount, $this->_itemsPerPage, $page, '');

        $p->setMaxPagesToShow($maxPagesToShow);

        $first = ptyRebuildUrl(array($this->_pageName => 1));
        $prev = ptyRebuildUrl(array($this->_pageName => $p->getPrevPage() ? $p->getPrevPage() : 1));
        $next = ptyRebuildUrl(array($this->_pageName => $p->getNextPage() ? $p->getNextPage() : $p->getNumPages()));
        $last = ptyRebuildUrl(array($this->_pageName => $p->getNumPages()));

        $out = <<<END
	<a href="$prev" class="prev">이전</a>
END;
        foreach ($p->getPages() as $item) {
            if ($item['num'] == "...") {
                $out .= "<a href='#'>{$item['num']}</a>";
                continue;
            }

            $on = "";
            $url = ptyRebuildUrl(array($this->_pageName => $item['num']));
            if ($item['isCurrent'])
                $on = " class='on'";
            $out .= "<a href='$url' $on>{$item['num']}</a>";
        }

        $out .= <<<END
	<a href="$next" class="next">다음</a>
END;

        return $out;
    }

    public function disable($id)
    {
        $id = (int)$id;
        $this->db->clear()->addFrom($this->_tableName)->addWhere("id = '$id'")->addSet("enabled", 0)->update();
    }

    public function enable($id)
    {
        $id = (int)$id;
        $this->db->clear()->addFrom($this->_tableName)->addWhere("id = '$id'")->addSet("enabled", 1)->update();
    }

    public function remove($id)
    {
        return $this->disable($id);
    }

    public function delete($id)
    {
        $id = (int)$id;
        $this->db->clear()->addFrom($this->_tableName)->addWhere("id = '$id'")->delete();
    }

    public function deleteBy($key, $value)
    {
        $value = addslashes($value);
        $this->db->clear()->addFrom($this->_tableName)->addWhere("$key = '$value'")->delete();
    }


    /**
     *
     * @param ptyItemModel $item
     *
     * @return ptyItemModel
     */
    public function add($item, $updateDescId = true)
    {
        /*
        if (get_class($item) == "platyFramework\\ptyArrayItemModel") {
            $item = static::buildItem($item);
            if (!count($item->_item))
                return NULL;
        }
        */

        unset($item->_item['id']);

        if ($item->_tableName == "")
            $item->_tableName = $this->getTableName();

        if ($this->_use_col_ip == true) {
            $item->ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
            /*
            $item->ip = "";
            if (isset($_SERVER) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $item->ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
            else if (isset($_SERVER) && isset($_SERVER['REMOTE_ADDR'])) $item->ip = $_SERVER['REMOTE_ADDR'];

            $item->ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER["REMOTE_ADDR"];
            */
        }

        if ($this->_use_col_userId == true) {
            if (!isset($item->_item['userId']))
                $item->userId = $this->signedInItem ? $this->signedInItem->userId : "";
        }


        if ($this->_use_col_serviceUserId == true) {
            if (!isset($item->_item['serviceUserId']))
                $item->serviceUserId = $this->signedInItem ? $this->signedInItem->serviceUserId : "";
        }

        if ($this->_use_col_regDateTime == true) {
            if (!isset($item->_item['regDateTime']))
                $item->_item['*regDateTime'] = "NOW()";
        }

//        if (!$this->onItemAdd($item)) return null;
//        if (!$item->onItemAdd($item)) return null;


        if (false) {
            if (is_callable([$this, 'onItemAdd'])) if (!$this->onItemAdd($item)) return null;
            if (is_callable([$item, 'onItemAdd'])) if (!$item->onItemAdd($item)) return null;

            // [TODO] callAction 의 onItemAdd 처리 필요
            // if (is_callable([$this, 'callAction'])) $this->callAction("onItemAdd", $item);
        }

        $this->db->clear()->addFrom($this->getTableName())->addSet($item->_item)->insert();
        $item->id = $this->db->getInsertId();

        if ($this->_use_col_descId == true) {
            if ($this->_useDescId && $updateDescId) {
                $item->descId = $item->id * -1;
                $item->updateWithItemName("descId");
            }
        }

        // [TODO] callAction 의 onItemAdded 처리 필요
        if (false) {
            if (is_callable([$this, 'onItemAdded'])) $item->onItemAdded($item);           // item's onItemAdded();
            if (is_callable([$item, 'onItemAdded'])) $this->onItemAdded($item);      // list's onItemAdded();
            if (is_callable([$this, 'callAction'])) $this->callAction("onItemAdded", $item);
        }

        return $item;
    }

    /**
     * 아이템이 추가되기 전 호출됩니다
     *
     * @param $item
     * @return bool
     */
    public function onItemAdd($item)
    {
        return true;

    }

    /**
     * 아이템이 추가된 후 호출됩니다
     *
     * @param $item
     */
    public function onItemAdded($item)
    {

    }

    /**
     * @param ptyItemModel $oldItem
     * @param ptyItemModel $item
     */
    public function edit($oldItem, $item)
    {
        if (!$this->onItemEdit($oldItem, $item)) return null;
        if (!$item->onItemEdit($oldItem, $item)) return null;

        /*
        $fileManager = new ptyfileItemsModel();
        if ($this->enableUploadFileMatchColumn)
            $fileManager->uploadAll('item', $this->_tableName, $item->item->id, $item);
        else
            $fileManager->uploadAll('item', $this->itemsModel->tableName, $item->item->id);
        */

        $item->updateWithItemName(array_keys($item->_item));

        $item->onItemEdited($oldItem, $item);
        $this->onItemEdited($oldItem, $item);

        return true;
    }

    /**
     * @param ptyItemModel $oldItem
     * @param ptyItemModel $item
     * @return bool
     */
    public function onItemEdit($oldItem, $item)
    {
        return true;
    }

    /**
     * @param ptyItemModel $oldItem
     * @param ptyItemModel $newItem
     * @return bool
     */
    public function onItemEdited($oldItem, $newItem)
    {
        return true;
    }

    /**
     * @return mixed
     */
    public function getTotalCount()
    {
        return $this->_totalCount;
    }

    public function getTotalPageCount()
    {
        // 13 - 10
        return ceil($this->_totalCount / $this->_itemsPerPage);
        // return (int)($this->totalCount / ($this->totalCount - $this->pageLimit));
    }

    /**
     * @return boolean
     */
    public function isEnableDescId()
    {
        return $this->enableDescId;
    }

    /**
     * @param string $tableName
     * @param string $key
     * @param null $value
     *
     * @return ptytableItemModel
     * @author cpueblo <cpueblo@platyhouse.com>
     */
    /*
    public static function buildItemWithEnabled($tableName, $key, $value = NULL)
    {
        $list = new static($tableName);

        return $list->getItemWithEnabled($key, $value);
    }

    public static function buildItemsWithEnabled($tableName, $key = NULL, $value = NULL)
    {
        $list = new static($tableName);

        return $list->getItemsBy($key, $value);
    }
    */


    /*
    public static function buildItem($tableName, $key, $value = NULL)
    {
        $list = new static($tableName);

        return $list->getItem($key, $value);
    }


    public static function buildItems($tableName, $key, $value = NULL)
    {
        $list = new static($tableName);
        return $list->getItems($key, $value);
        // return $list->getItemsBy($key, $value);

    }

    public static function deleteItem($tableName, $key, $value = NULL)
    {
        $list = new static($tableName);

        $list->init(FALSE);
        if (is_array($key) && $value == NULL) {
            foreach ($key as $k => $v)
                $list->db->addWhereEqual($k, $v);
        } else {
            $list->db->addWhereEqual($key, $value);
        }

        $list->db->sql_query("delete from {$tableName} where " . $list->db->getWhere(FALSE));
    }
    */

    /**
     * @return ptyTableItemModel $item
     */
    /*
    public function getItem($key, $value = NULL)
    {
        $this->db->addSelect("*");
        $item = $this->getItemBy($key, $value);

        return $item;
    }
    */

    /**
     * @param boolean $enableDescId
     */
    public function setEnableDescId($enableDescId)
    {
        $this->enableDescId = $enableDescId;

        return $this;
    }

    /**
     * @return boolean
     */
    public function isEnableConveringIndex()
    {
        return $this->enableConveringIndex;
    }

    /**
     * @param boolean $enableConveringIndex
     */
    public function setEnableConveringIndex($enableConveringIndex)
    {
        $this->enableConveringIndex = $enableConveringIndex;

        return $this;
    }

    /**
     * @param $i
     *
     * @return ptyItemModel | $this->_itemModel
     */
    public function getItemById($i)
    {
        return $this->clear()->getItemBy(array("{$this->_tableName}.id" => $i));
    }

    /**
     * @param      $key
     * @param null $value
     *
     * @return $this->_itemModel
     */
    function getItemBy($key, $value = null)
    {
        // $this->clear();
        if (is_array($key) && $value == NULL) {
            foreach ($key as $k => $v)
                $this->db->addWhereEqual($k, $v);
        } else {
            $this->db->addWhereEqual($key, $value);
        }

        $item = $this->getItem();
        debug($item, "getItemBy");
        return $item;

        /*
        $this->clear();

        if (is_array($key) && $value == NULL) {
            foreach ($key as $k => $v)
                $this->db->addWhereEqual($k, $v);
        } else {
            $this->db->addWhereEqual($key, $value);
        }

        $q = "SELECT a.* from (
          SELECT id FROM ".$this->db->getFrom(FALSE)."
          WHERE ".$this->db->getWhere(FALSE)."
          ) b join ".$this->db->getFrom(FALSE)." a on b.id = a.id
          ";

        $item = $this->db->sql_fetch($q);

        if ($item) {
            $className = $this->itemModelClassName;
            $newItem = $className::buildItem($this->tableName, $item);

            return $newItem;
        } else {
            return NULL;
        }
        */
    }

    /**
     * @return null|ptyItemModel
     */
    function getItem()
    {
        $oldItemsePerPage = $this->_itemsPerPage;
        $this->setItemsPerPage(1);
        $this->setPageIndex(1);
        $items = $this->getItems();
        $this->setItemsPerPage($oldItemsePerPage);
        if (count($items))
            return $items[0];
        else
            return NULL;
    }

    /**
     * 페이지당 보여줄 개수를 지정합니다.
     * 1 이상 입력해야 동작됩니다
     *
     * @param int $_itemsPerPage
     */
    public function setItemsPerPage($_itemsPerPage)
    {
        $this->_itemsPerPage = (int)$_itemsPerPage;
        $this->db->setLimit($this->_itemsPerPage);
        return $this;
    }

    /**
     * @param bool $returnType 0 : return with array, 1 : return with ptyItemModel, 2 : return With sql_fetch_array
     * @return ptyItemModel[]
     * @author cpueblo <cpueblo@platyhouse.com>
     */
    function getItems($returnType = 1)
    {
        // 기본 쿼리 적용
        // $this->db->setDebug(1);
        // $this->db->addWhereParam($this->request->request, ["page", "sec_petName"]);

        if (isDebug())
            $this->db->setDebug(1);

        debug($this->_itemsPerPage, "_itemsPerPage");

        // select 기본 설정 체크 {$this->>tableName}.* 로 설정
        $select = $this->db->getSelect(false);
        if (!count($select))
            $this->db->addSelect("{$this->_tableName}.*");

        // 앞에 선언한 select 가 있다면 * 추가후 select 를 처리하고 그렇지 않으면 기본값을 설정
        $select2 = $this->db2->getSelect(false);
        if (count($select2)) {
            foreach ($select2 as $k => $v)
                $this->db->addSelect($v);
        }

        // from 기본 설정 체크
        $from = $this->db->_SQL_FROM_ARRAY;
        if (!count($from))
            $this->db->addFrom("{$this->_tableName}");

        // order by 기본 설정 체크
        $orderby = $this->db->_SQL_ORDERBY;

        if (!count($orderby) || $orderby == "") {
            if ($this->_useDescId)
                $this->db->addOrderBy("{$this->_tableName}.descId");
            else
                $this->db->addOrderBy("{$this->_tableName}.{$this->_primaryColumnName} desc");
        } else {
            $this->db->addOrderBy("{$this->_tableName}.{$this->_primaryColumnName} desc");
        }

        $q = "";
        if ($this->_useCoveringIndex) {
            $q = $this->db->getSelect() . " /* CACHE */ FROM (SELECT `{$this->_tableName}`.`id` FROM " . $this->db->getFrom(FALSE) . " " . $this->db->GetWhere() . $this->db->getHaving() . $this->db->GetGroupBy() . $this->db->getOrderBy() . $this->db->GetLimit() . ") coveringIndex INNER JOIN {$this->_tableName} ON coveringIndex.id = {$this->_tableName}.id " . $this->db->getJoin();
        }

        if ($returnType == 0 || $returnType == 1) {
            $lst = $this->db->sql_list($q);
        } else if ($returnType == 2) {
            $result = $this->db->sql_query($q);
            return $result;
        } else if ($returnType == 3) {
            return $this->db->sql_list4($q);
        }

        if ($this->_itemsPerPage > 1) {
            $q = "";
            if ($this->_useTableSchemaAtCount) {
                $q = "SELECT table_rows FROM information_schema.tables where table_name = '{$this->_tableName}'";
            } else if ($this->_useCoveringIndexAtCount) {
                $q = "SELECT COUNT(`{$this->_tableId}`.id) FROM $this->_tableName";
            }

            $this->_totalCount = $this->db->getCount($q);
        } else {
            $this->_totalCount = count($lst);
        }

        if ($returnType == 1) {
            /** @var ptyItemModel $itemModel */
            $itemModel = $this->_itemModel;

            $lst = $itemModel::buildTableItems($this->_tableName, $lst, $this->_totalCount);
        }

        return $lst;
    }

    function getItemBy_old($key, $value = NULL)
    {
        $this->db->setLimit(0);

        if (count($this->db->getSelect(FALSE)) < 1 || $this->db->getSelect(FALSE) == "")
            $this->db->addSelect("*");

        // if ($this->enabled) $this->db->addWhereEqual("{$this->tableName}.enabled", "1");

        if (is_array($key) && $value == NULL) {
            foreach ($key as $k => $v)
                $this->db->addWhereEqual($k, $v);
        } else {
            $this->db->addWhereEqual($key, $value);
        }
        $item = $this->db->sql_fetch();

        if ($item) {
            $className = $this->_itemModel;
            $newItem = $className::buildItem($this->_tableName, $item);

            return $newItem;
        } else {
            return NULL;
        }
    }

    public function getItemByPos($i)
    {
        $this->db->clear();
        $item = $this->db->sql_fetch("SELECT * FROM {$this->_tableName} LIMIT $i, 1");
        if ($item) {
            $className = $this->_itemModel;
            $newItem = $className::buildItem($this->_tableName, $item);

            return $newItem;
        } else {
            return NULL;
        }
    }

    /**
     * 페이지 번호를 지정합니다.
     * 1 이상 입력해야 동작됩니다
     *
     * @param int $pageIndex
     */
    public function setPageIndex($pageIndex)
    {
        $this->pageIndex = (int)$pageIndex;
        if ($this->pageIndex < 1)
            $this->pageIndex = 1;
        $this->db->setPageIndex($this->pageIndex);
        return $this;
    }

    public function setDebug($b = TRUE)
    {
        $this->db->setDebug($b);
        $this->db2->setDebug($b);

        return $this;
    }

    /**
     * @param $keyValues
     * @param bool $returnType 0 : return with array, 1 : return with ptyItemModel, 2 : return for sql_fetch_array
     * @return ptyItemModel[]
     */
    function getItemsBy($keyValues, $returnType = 1)
    {
        // $this->clear();
        // if (is_array($key) && $value == NULL) {
        foreach ($keyValues as $k => $v)
            $this->db->addWhereEqual($k, $v);
        /*
    } else {
        $this->db->addWhereEqual($key, $value);
    }
        */

        /*
        $className = $this->itemModelClassName;

        $this->db->setLimit(0);
        $this->db->addOrderBy("{$this->tableName}.descId");

        if (count($this->db->getSelect(FALSE)) < 1 || $this->db->getSelect(FALSE) == "")
            $this->db->addSelect("*");

        if (is_array($key) && $value == NULL) {
            foreach ($key as $k => $v)
                $this->db->addWhereEqual($k, $v);
        } else {
            $this->db->addWhereEqual($key, $value);
        }
        $lst = $this->db->sql_list();
        $lst = $className::buildWithItems($this->tableName, $lst);

        */

        return $this->getItems($returnType);
    }

    function truncate()
    {
        $this->db->sql_query("TRUNCATE {$this->_tableName}");
    }

    /**
     * remove 의 예시입니다
     *
     * @param $id
     * @return null
     */
    public function exRemove($id)
    {
        /** @var jbcarsItemModel $item */
        $item = $this->getItemBy(["serviceUserId" => $this->signedInItem->serviceUserId, "userId" => $this->signedInItem->userId, "enabled" => 1, "id" => $id]);
        if (!$item) {
            return null;
        }

        $item->enabled = 0;
        $item->updatewithItemName(["enabled"]);
    }

    /**
     * getItems 의 예시입니다
     * @return ptyItemModel[]
     */
    public function exGetItemsWithJoin()
    {
        $this->db->clear();
        $this->db->addSelect("{$this->_tableName}.*, joinTableName.name as driverName");
        $this->db->addJoin("LEFT JOIN joinTableName ON joinTableName.id = {$this->_tableName}.driverId");
        $items = $this->getItemsBy([
            "`{$this->_tableName}`.serviceUserId" => $this->signedInItem->serviceUserId,
            "`{$this->_tableName}`.userId" => $this->signedInItem->userId,
            "`{$this->_tableName}`.enabled" => 1], 0);

        return $items;
    }

    /**
     * getItems 의 예시입니다
     * @return ptyItemModel[]
     */
    public function exGetItems()
    {
        $this->db->clear();
        $this->db->addSelect("{$this->_tableName}.*");
        $items = $this->getItemsBy([
            "`{$this->_tableName}`.serviceUserId" => $this->signedInItem->serviceUserId,
            "`{$this->_tableName}`.userId" => $this->signedInItem->userId,
            "`{$this->_tableName}`.enabled" => 1], 0);

        return $items;
    }

    public function exAddItem($a,
                              $picture,
                              $notes)
    {
        $itemsModel = jbcarsItemsModel::build();

        /** @var ptyItemModel $item */
        $itemClassName = $this->_itemModel;
        $item = $itemClassName::build();
        $item->a = $a;
        $item->b = $b;
        $itemsModel->add($item);

        $fileItemsModel = ptyfileItemsModel::build();
        $fileItem = $fileItemsModel->addFileFromBuffer($picture, $this->_tableName, $item->id, "picture", 0);
        $item->picture = $fileItem->externalUrl;

        $item->updateWithItemName(["picture"]);

        return $item;
    }

    public function getServiceUserIds()
    {
        $this->db->clear();
        $this->db->addFrom($this->_tableName);
        $this->db->addSelect("serviceUserId");
        $this->db->addGroupBy("serviceUserId");
        $serviceUserIds = $this->db->sql_list2();
        return $serviceUserIds;
    }

    /**
     * string 을 이용하여 테이블을 분리할때 사용됩니다
     *
     * @param $string
     * @param int $div
     * @return int
     */
    public function _getSplitTableId($string, $div = 100)
    {
        if ((int)$string > 0) {
            return sprintf("%02d", (int)substr($string, -2) % $div);
        }
        if ($string != "") {

            $sum = 0;
            for ($i = 0; $i < strlen($string); $i++)
                $sum += ord($string[$i]);

            $sum = $sum % $div;
            return $sum;
        } else
            return "";
    }

    /**
     * 테이블에 _split_ 을 붙여 100개의 테이블로 나눕니다. 주로 userId, primary id 를 기준으로 진행합니다
     * @param string $someId
     */
    public function setTableSplitId($someId = "")
    {
        $this->_splitTableId = $this->_getSplitTableId($someId);
    }

    public function getTableName()
    {
        if ($this->_splitTableId != "")
            return $this->_tableName . "_split_" . $this->_splitTableId;
        else
            return $this->_tableName;
    }

    function deleteTable()
    {
        $this->db->sql_query("DROP TABLE IF EXISTS `{$this->_tableName}`");
    }
}
