<?php

$cms["modules"]["ecs.mod.php"] = array(
    "name" => "ecs_module_name",
    "description" => "ecs_module_description",
    "files" => array(
        ".cms/mod/ecs.mod.php",
        ".cms/css/ecs.less",
        ".cms/css/ecs.css",
        ".cms/js/ecs.js",
        ".cms/lang/ru_RU.UTF-8/ecs.mod.php",
    ),
);

// По умолчанию модуль скрыт. Пока не доделан.
if ( ! isset( $cms["config"]["admin_sections"]["ecs"]["hide"] ) ) {
    $cms["config"]["admin_sections"]["ecs"]["hide"] = true;
}

// Если модуль отключен
if ( ! empty( $cms["config"]["ecs.mod.php"]["disabled"] ) ) {
    return;
}

if ( is_admin() ) {
    if ( empty( $_COOKIE["ecs_pager"] ) ) {
        cms_set_sess_cookie( "ecs_pager", 100 );
    }
    hook_add_fn( "create_tables", "ecs_create_tables" );
    hook_add_fn( "admin_header", "ecs_admin_header" );
    hook_add_fn( "admin", "ecs_admin" );
    hook_add_fn( "api", "ecs_api" );
}

function ecs_create_tables() {
    global $cms;

    if ( empty( $cms["pdo"] ) ) {
        return;
    }

    $type = $cms["pdo"]->getAttribute( PDO::ATTR_DRIVER_NAME );

    if ( $type === "mysql" ) {
        $id_column = "id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY";
    } elseif ( $type === "pgsql" ) {
        $id_column = "id BIGSERIAL PRIMARY KEY";
    } else {
        return;
    }

    // При создании сущности, чтобы она хоть как-то могла существовать,
    // в таблицу добавляется строчка с пустым компонентом, component="" и component_id=0.
    // Далее уже к сущности можно добавлять другие компоненты - имена таблиц,
    // которые могут даже не подозревать что они являются частью сущности.
    // Таким образом можно использовать данные из любых других модулей не оповещая их об этом.
    $sql = "
    CREATE TABLE IF NOT EXISTS entity (
        {$id_column},
        entity_id INT NOT NULL,
        component VARCHAR(64) NOT NULL DEFAULT '',
        component_id INT NOT NULL
    );
    ";

    try {
        $cms["pdo"]->exec( $sql );
    } catch ( PDOException $e ) {
        error_log( $e->getMessage() );
    }
}

function ecs_admin_header() {
    global $cms;
    if ( is_admin_header_on( "ecs.mod.php" ) ) {
        echo "<link rel=stylesheet href='{$cms["base_path"]}css/ecs.css'>\n";
        echo "<script src='{$cms["base_path"]}js/ecs.js'></script>\n";
    }
}

function ecs_admin() {
    global $cms;
    if ( is_admin_header_on( "ecs.mod.php" ) ) {
        $page  = "
<div class=header>
    <div class='add button'>
        <span class=desktop>" . __( "add_button" ) . "</span>
    </div>
    " . widget( "search_widget.html" ) . "
    <div class='button trash icon' title='" . __( "del_button" ) . "'>
        <span></span>
    </div>
</div>
<div class=main>
    <div class=entitys></div>
</div>
" . widget( "footer_pager.html" );

        $section_id = "entity";
        if ( empty( $cms["config"]["ecs.mod.php"]["menu"][$section_id] ) ) {
            $cms["config"]["ecs.mod.php"]["menu"][$section_id] = array(
                "title" => "entity",
                "sort"  => 10,
                "section" => "ecs",
                "hide" => true,
            );
        }
        $cms["admin_pages"][$section_id] = $page;
    }

}

#region api
function ecs_api() {
    global $cms;

    if ( empty( $cms["pdo"] ) ) {
        return;
    }

    if ( ! empty( $_POST["fn"] ) ) {
        switch ( $_POST["fn"] ) {
            case "create_entity":
                // Определяем следующий свободный entity_id
                try {
                    $query = "SELECT MAX(entity_id) as max_id FROM entity";
                    $stmt = $cms["pdo"]->prepare( $query );
                    $stmt->execute();
                    $result = $stmt->fetch( PDO::FETCH_ASSOC );
                    
                    
                    if ( empty( $result["max_id"] ) ) {
                        $entity_id = 1;
                    } else {
                        $entity_id = (int) $result["max_id"] + 1;
                    }

                    // Создаем сущность с пустыми компонентами
                    $query = "INSERT INTO entity (entity_id, component, component_id) VALUES (?, ?, ?)";
                    $stmt = $cms["pdo"]->prepare( $query );
                    $stmt->execute( array(
                        $entity_id,
                        "", // Пустой компонент
                        0   // Нулевой ID компонента
                    ) );

                    // $_POST["count"] = 1;
                } catch ( PDOException $e ) {
                    error_log( $e->getMessage() );
                }

            // break; Отменяем break чтобы получить обновленный список сущностей

            // Универсальная функция, работающая с поиском или без него.
            case "get_entity_list":
                // Смещение
                if ( isset( $_POST["offset"] ) ) {
                    $offset = (int) $_POST["offset"];
                } else {
                    $offset = 0;
                }

                // Количество
                if ( ! empty( $_POST["count"] ) ) {
                    $limit = (int) $_POST["count"];
                } elseif ( ! empty( $_COOKIE["entity_pager"] ) ) {
                    $limit = (int) $_COOKIE["entity_pager"];
                } else {
                    $limit = 100;
                }
                // Общее количество
                $count = 0;

                // Компонент для поиска
                if ( ! empty( $_POST["component"] ) ) {
                    $search_component = $_POST["component"];
                } else {
                    $search_component = "";
                }

                // Поле компонента для поиска
                if ( ! empty( $_POST["field"] ) ) {
                    $search_field = $_POST["field"];
                } else {
                    $search_field = "";
                }

                // Регулярное выражение для поиска
                if ( ! empty( $_POST["search"] ) ) {
                    $search = $_POST["search"];

                    // Shift разбивает искомое на символы
                    if ( $_POST["Shift"] === "true" ) {
                        $search = preg_replace( "/\s/u", "", $search );
                        $search = preg_split( '//u', $search, -1, PREG_SPLIT_NO_EMPTY );
                        
                        // Совместимость с php-5.2.17+
                        $escaped_search = array();
                        foreach ($search as $char) {
                            $escaped_search[] = preg_quote($char, '/');
                        }

                        $search = implode( ".*", $search );
                    }

                    $search = ".*" . $search . ".*";
                    $search_regex = preg_prepare( $search );
                } else {
                    $search = "";
                    $search_regex = "";
                }

                $start = microtime( true );
                $overload = false;
                $notify_html = "";

                try {
                    // Пока что делаем без оптимизаций скорости, перебирая все подряд.
                    // Сначала получаем id, потому что компоненты могут быть раскиданы по таблице.
                    $query = "SELECT DISTINCT(entity_id) FROM entity GROUP BY entity_id ORDER BY MAX(id) DESC";
                    $stmt_entity = $cms["pdo"]->prepare( $query );
                    $stmt_entity->execute();

                    // Возвращаемые сущности
                    $entitys_html = array();

                    // Перебор всех сущностей
                    while ( $entity = $stmt_entity->fetch( PDO::FETCH_ASSOC ) ) {

                        // Извлекаем компоненты сущности
                        $query = "SELECT * FROM entity WHERE entity_id = ?";
                        $stmt_component_id = $cms["pdo"]->prepare( $query );
                        $stmt_component_id->execute( array( $entity["entity_id"] ) );

                        while ( $component_id = $stmt_component_id->fetch( PDO::FETCH_ASSOC ) ) {

                            $component = $component_id["component"];
                            $component_id = $component_id["component_id"];

                            if ( ! empty( $component ) && ! empty( $component_id ) ) {

                                $query = "SELECT * FROM {$component} WHERE id = ?";
                                $stmt_component = $cms["pdo"]->prepare( $query );
                                $stmt_component->execute( $component_id );
                                while ( $component_row = $stmt_component->fetch( PDO::FETCH_ASSOC ) ) {
                                    if ( ! isset( $entity[$component] ) ) {
                                        $entity[$component] = $component_row;
                                    } elseif ( array_is_list( $entity[$component] ) ) {
                                        $entity[$component][] = $component_row;
                                    } else {
                                        $entity[$component] = array(
                                            $entity[$component],
                                            $component_row,
                                        );
                                    }
                                }

                            }
                        }

                        // Поиск
                        if ( empty( $search_regex ) ) {
                            $found = true;
                        } else {
                            $found = false;

                            if ( isset( $entity[$search_component] ) ) {
                                // Если это массив компонентов
                                if ( array_is_list( $entity[$search_component] ) ) {
                                    // Проверяем каждый компонент
                                    foreach ( $entity[$search_component] as $component ) {
                                        if ( isset( $component[$search_field] ) && preg_match( $search_regex, $component[$search_field] ) ) {
                                            $found = true;
                                            break; // Нашли совпадение, достаточно
                                        }
                                    }
                                } else {
                                    // Одиночный компонент
                                    if ( isset( $entity[$search_component][$search_field] ) && preg_match( $search_regex, $entity[$search_component][$search_field] ) ) {
                                        $found = true;
                                    }
                                }
                            }
                        }

                        // Добавляем если найдено
                        if ( $found ) {
                            $count = $count + 1; // общее количество найденных сущностей
                            if ( $offset > 0 ) {
                                $offset = $offset - 1;
                            } elseif ( $limit > 0 ) {
                                $limit = $limit - 1;
                                
                                // Создаем разметку
                                $html = "
<div class=entity data-id={$entity["entity_id"]}>
    <div class=header>
        <div>Заголовок</div>
        <input type=checkbox name=del>
    </div>
    <div class=main>
        <div class=row1>
            " . htmlspecialchars( json_encode( $entity, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ) ) . "
        </div>
        <div class=row1>
            Строчка добавленная другим модулем
        </div>
        <!--entity-lines-->
    </div>
    <div class=footer>
        <div class='button b1'>
            <span>Button 1</span>
        </div>
        <div class='button b2'>
            <span>Button 2</span>
        </div>
        <div class='button b3'>
            <span>Button 3</span>
        </div>
        <div>Кнопки других модулей</div>
        <!--entity-buttons-->
    </div>
</div>
                                ";
                                array_push( $entitys_html, array(
                                    "id" => $entity["entity_id"],
                                    "html" => $html,
                                ) );
                            }
                        }


                        // Следим за перегрузкой
                        if ( microtime( true ) - $start > 1 ) { // 1 секунда
                            $overload = true;
                            $notify_html = __( "server_overloaded_xxx" );
                            $notify_html = str_replace( "xxx", $count, $notify_html );
                            break;
                        }
                    }

                    // Возвращаем ответ
                    echo( json_encode( array(
                        "result" => array(
                            "entitys" => $entitys_html,
                            "offset"   => $offset, 
                            "count" => $count,
                            "search"   => $search,
                            "notify_html" => $notify_html,
                        )
                    ) ) );
                } catch ( PDOException $e ) {
                    error_log( $e->getMessage() );
                }
            break;
        }
    }
}
#endregion api
