<?php
/**
 * PAGEDATA CLASS
 *
 * Responsible for the cohesion of page_list, page_list_item & page_list_item_data
 * and the consutrct they create - pagedata.
 *
 * @package
 * @author Rihards Silins
 * @copyright MTC Media 2016
 * @version 4 28/10/2016
 * @access public
 *
 */
use Mtc\Cms\Models\PageListItemData as PageListItemData;
use Mtc\Cms\Models\PageListItem as PageListItem;
use Mtc\Cms\Models\PageList as PageList;

Class Pagedata
{
    /**
     * Page this pagedata belongs to
     * @var int $page_id
     */
    public $page_id = 0;
    /**
     * Pagedata consutruct containing altleast one page_list, page_list_item & page_list_item_data
     *
     * Default pagedata with a single list that has a single item
     * witch again has only one data looks like this (if all the params are set, note only some are required) -
     * $this->pagedata = array(
     *     0 => array(
     *         'id'                  => 0,
     *         'page_id'             => 0,
     *         'name'                => "",
     *         'type'                => "",
     *         'setup'               => 0,
     *         'lock'                => 0,
     *         'info'                => "",
     *         'order'               => 0,
     *         'atleast_one'         => 1,
     *         'allow_more'          => 0,
     *         'allow_more_max'      => 0,
     *         'allow_more_min'      => 0,
     *         'add_list_item_to_top'=> 0,
     *         'more_text'           => "Add another one",
     *         'settings'            => "",
     *         'data1'               => "",
     *         'data2'               => "",
     *         'data3'               => "",
     *         'items'               => array(
     *             0 => array (
     *                 'id'            => 0,
     *                 'page_id'       => 0,
     *                 'page_list_id'  => 0,
     *                 'type'          => "",
     *                 'order'         => 0,
     *                 'data1'         => "",
     *                 'data'          => array(
     *                     0 => array(
     *                         'id'                => 0,
     *                         'page_id'           => 0,
     *                         'page_list_id'      => 0,
     *                         'page_list_item_id' => 0,
     *                         'name'              => "",
     *                         'info'              => "",
     *                         'order'             => 0,
     *                         'type'              => "",
     *                         'setup'             => 0,
     *                         'lock'              => 0,
     *                         'value'             => "",
     *                         'regex'             => "",
     *                         'mime'              => "",
     *                         'required'          => 0,
     *                         'settings'          => "",
     *                         'css_class'         => "",
     *                         'options'           => "",
     *                         'language'          => "",
     *                         'uuid'              => "",
     *                         'data1'             => "",
     *                         'data2'             => "",
     *                         'data3'             => "",
     *                     ),
     *                 )
     *             ),
     *         )
     *     ),
     * );
     *
     * @var mixed[][][] $pagedata
     *
     */
    public $pagedata = array();
    /**
     * Langauge this pagedata is in
     * @var string $language language code
     */
    private $language = 0;
    /**
     * Pagedata::setLangauge()
     * Language setter.
     * @param string $language language code
     */
    public function setLanguage($language = 0) {
        $this->language = $language;
    }
    /**
     * Class Pagedata()
     * Construct function.
     */
    public function __construct () {
        $this->page_id = 0;
        $this->pagedata = array();
    }
    /**
     * Pagedata::save()
     *
     * @return bool
     *
     */
    public function save() {

        // if page_id is not set - return false
        // can't save pagedata attached to no page
        if (empty($this->page_id)) {
            return false;
        }

        $params = [
            &$this,
            $this->page_id,
        ];
        HooksAdapter::do_action_ref_array(__CLASS__ . '/' . __FUNCTION__, [$params]);

        // loop through lists
        for ($i=0; $i<count($this->pagedata); $i++) {
            // if existing list
            if  (
                !empty($this->pagedata[$i]['id']) &&
                ($page_list = PageList::find($this->pagedata[$i]['id'])) != null) {
                // existing list
                $page_list->page_id = $this->page_id;

                if (isset($this->pagedata[$i]['name']) && !empty($this->pagedata[$i]['name'])) {
                    $page_list->name = $this->pagedata[$i]['name'];
                } else {
                    return false;
                }

                $check_vars_for_isset = [
                    "type",
                    "info",
                    "settings",
                    "data1",
                    "data2",
                    "data3"
                ];
                foreach ($check_vars_for_isset as $var_name) {
                    if (isset($this->pagedata[$i][$var_name])) {
                        $page_list->{$var_name} = $this->pagedata[$i][$var_name];
                    }
                }

                $check_vars_for_isset_and_is_numberic = [
                    "setup",
                    "lock",
                    "order",
                    "atleast_one",
                    "allow_more",
                    "allow_more_max",
                    "allow_more_min",
                    "add_list_item_to_top"
                ];
                foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                    if (isset($this->pagedata[$i][$var_name]) && is_numeric($this->pagedata[$i][$var_name])) {
                        $page_list->{$var_name} = $this->pagedata[$i][$var_name];
                    }
                }

                if (isset($this->pagedata[$i]['more_text']) && !empty($this->pagedata[$i]['more_text'])) {
                    $page_list->more_text = $this->pagedata[$i]['more_text'];
                }

                if ($page_list->save() === false) {
                    return false;
                }
            } else {
                // else if new list
                $page_list = new PageList();
                $page_list->page_id = $this->page_id;

                if (isset($this->pagedata[$i]['name']) && !empty($this->pagedata[$i]['name'])) {
                    $page_list->name = $this->pagedata[$i]['name'];
                } else {
                    return false;
                }

                $check_vars_for_isset = [
                    "type",
                    "info",
                    "settings",
                    "data1",
                    "data2",
                    "data3"
                ];
                foreach ($check_vars_for_isset as $var_name) {
                    if (isset($this->pagedata[$i][$var_name])) {
                        $page_list->{$var_name} = $this->pagedata[$i][$var_name];
                    }
                }

                $check_vars_for_isset_and_is_numberic = [
                    "setup",
                    "lock",
                    "atleast_one",
                    "allow_more",
                    "allow_more_max",
                    "allow_more_min",
                    "add_list_item_to_top"
                ];
                foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                    if (isset($this->pagedata[$i][$var_name]) && is_numeric($this->pagedata[$i][$var_name])) {
                        $page_list->{$var_name} = $this->pagedata[$i][$var_name];
                    }
                }

                if (isset($this->pagedata[$i]['more_text']) && !empty($this->pagedata[$i]['more_text'])) {
                    $page_list->more_text = $this->pagedata[$i]['more_text'];
                }

                if (isset($this->pagedata[$i]['order']) && is_numeric($this->pagedata[$i]['order'])) {
                    $page_list->order = $this->pagedata[$i]['order'];
                } else {

                    // generate page_list order
                    $pl_with_largest_order = PageList::where("page_id", $this->page_id)->orderBy("order", "DESC")->first(["order"]);
                    if ($pl_with_largest_order != null) {
                        $page_list->order = $pl_with_largest_order->order + 1;
                    } else {
                        $page_list->order = 0;
                    }

                }

                if ($page_list->save() === false) {
                    return false;
                }

                $this->pagedata[$i]['id'] = $page_list->id;
            }

            // loop through list items
            for ($j=0; $j<count($this->pagedata[$i]['items']); $j++) {

                // if existing item
                if  (
                    !empty($this->pagedata[$i]['items'][$j]['id']) &&
                    ($page_list_item = PageListItem::find($this->pagedata[$i]['items'][$j]['id'])) != null) {
                    // existing item

                    $page_list_item->page_id = $this->page_id;

                    $page_list_item->page_list_id = $this->pagedata[$i]['id'];

                    $check_vars_for_isset = [
                        "type",
                        "data1",
                    ];
                    foreach ($check_vars_for_isset as $var_name) {
                        if (isset($this->pagedata[$i]['items'][$j][$var_name])) {
                            $page_list_item->{$var_name} = $this->pagedata[$i]['items'][$j][$var_name];
                        }
                    }

                    if (isset($this->pagedata[$i]['items'][$j]['order']) && is_numeric($this->pagedata[$i]['items'][$j]['order'])) {
                        $page_list_item->order = $this->pagedata[$i]['items'][$j]['order'];
                    }

                    if ($page_list_item->save() === false) {
                        return false;
                    }
                } else {
                    // else if new item
                    $page_list_item = new PageListItem();
                    $page_list_item->page_id = $this->page_id;

                    $page_list_item->page_list_id = $this->pagedata[$i]['id'];

                    $check_vars_for_isset = [
                        "type",
                        "data1",
                    ];
                    foreach ($check_vars_for_isset as $var_name) {
                        if (isset($this->pagedata[$i]['items'][$j][$var_name])) {
                            $page_list_item->{$var_name} = $this->pagedata[$i]['items'][$j][$var_name];
                        }
                    }

                    if (isset($this->pagedata[$i]['items'][$j]['order']) && is_numeric($this->pagedata[$i]['items'][$j]['order'])) {
                        $page_list_item->order = $this->pagedata[$i]['items'][$j]['order'];
                    } else {

                        // get page list item with largest order
                        $pli_with_largest_order = PageListItem::where("page_list_id", $this->pagedata[$i]['id'])->orderBy("order", "DESC")->first(["order"]);
                        if (!empty($pli_with_largest_order)) {
                            $page_list_item->order = $pli_with_largest_order->order + 1;
                        } else {
                            $page_list_item->order = 0;
                        }

                    }

                    if ($page_list_item->save() === false) {
                        return false;
                    }

                    $this->pagedata[$i]['items'][$j]['id'] = $page_list_item->id;
                }


                // loop through list item data
                for ($k=0; $k<count($this->pagedata[$i]['items'][$j]['data']); $k++) {

                    // if existing data
                    if  (
                        !empty($this->pagedata[$i]['items'][$j]['data'][$k]['id']) &&
                        ($page_list_item_data = PageListItemData::find($this->pagedata[$i]['items'][$j]['data'][$k]['id'])) != null) {
                        // existing data

                        $page_list_item_data->page_id = $this->page_id;

                        $page_list_item_data->page_list_id = $this->pagedata[$i]['id'];

                        $page_list_item_data->page_list_item_id = $this->pagedata[$i]['items'][$j]['id'];


                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['name']) && !empty($this->pagedata[$i]['items'][$j]['data'][$k]['name'])) {
                            $page_list_item_data->name = $this->pagedata[$i]['items'][$j]['data'][$k]['name'];
                        } else {
                            return false;
                        }

                        $check_vars_for_isset = [
                            "info",
                            "value",
                            "regex",
                            "mime",
                            "settings",
                            "css_class",
                            "options",
                            "language",
                            "uuid",
                            "data1",
                            "data2",
                            "data3",
                        ];
                        foreach ($check_vars_for_isset as $var_name) {
                            if (isset($this->pagedata[$i]['items'][$j]['data'][$k][$var_name])) {
                                $page_list_item_data->{$var_name} = $this->pagedata[$i]['items'][$j]['data'][$k][$var_name];
                            }
                        }

                        $check_vars_for_isset_and_is_numberic = [
                            "setup",
                            "lock",
                            "order",
                            "required"
                        ];
                        foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                            if (isset($this->pagedata[$i]['items'][$j]['data'][$k][$var_name]) && is_numeric($this->pagedata[$i]['items'][$j]['data'][$k][$var_name])) {
                                $page_list_item_data->{$var_name} = $this->pagedata[$i]['items'][$j]['data'][$k][$var_name];
                            }
                        }

                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['type']) && !empty($this->pagedata[$i]['items'][$j]['data'][$k]['type'])) {
                            $page_list_item_data->type = $this->pagedata[$i]['items'][$j]['data'][$k]['type'];
                        }

                        if ($page_list_item_data->save() === false) {
                            return false;
                        }
                    } else {
                        // elseif new data

                        $page_list_item_data                    = new PageListItemData();
                        $page_list_item_data->page_id           = $this->page_id;
                        $page_list_item_data->page_list_id      = $this->pagedata[$i]['id'];
                        $page_list_item_data->page_list_item_id = $this->pagedata[$i]['items'][$j]['id'];

                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['name']) && !empty($this->pagedata[$i]['items'][$j]['data'][$k]['name'])) {
                            $page_list_item_data->name = $this->pagedata[$i]['items'][$j]['data'][$k]['name'];
                        } else {
                            return false;
                        }

                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['order']) && is_numeric($this->pagedata[$i]['items'][$j]['data'][$k]['order'])) {
                            $page_list_item_data->order = $this->pagedata[$i]['items'][$j]['data'][$k]['order'];
                        } else {
                            // generate page_list_item_order
                            $plid_with_largest_order = PageListItemData::where("page_list_item_id", $this->pagedata[$i]['items'][$j]['id'])
                                ->orderBy("order", "DESC")
                                ->take(1)
                                ->get();
                            if (count($plid_with_largest_order) > 0) {
                                $page_list_item_data->order = $plid_with_largest_order[0]->order + 1;
                            } else {
                                $page_list_item_data->order = 0;
                            }
                        }

                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['type']) && !empty($this->pagedata[$i]['items'][$j]['data'][$k]['type'])) {
                            $page_list_item_data->type = $this->pagedata[$i]['items'][$j]['data'][$k]['type'];
                        }

                        $check_vars_for_isset = [
                            "info",
                            "value",
                            "regex",
                            "mime",
                            "settings",
                            "css_class",
                            "options",
                            "language",
                            "uuid",
                            "data1",
                            "data2",
                            "data3"
                        ];
                        foreach ($check_vars_for_isset as $var_name) {
                            if (isset($this->pagedata[$i]['items'][$j]['data'][$k][$var_name])) {
                                $page_list_item_data->{$var_name} = $this->pagedata[$i]['items'][$j]['data'][$k][$var_name];
                            }
                        }

                        $check_vars_for_isset_and_is_numberic = [
                            "setup",
                            "lock",
                            "required"
                        ];
                        foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                            if (isset($this->pagedata[$i]['items'][$j]['data'][$k][$var_name]) && is_numeric($this->pagedata[$i]['items'][$j]['data'][$k][$var_name])) {
                                $page_list_item_data->{$var_name} = $this->pagedata[$i]['items'][$j]['data'][$k][$var_name];
                            }
                        }

                        if (isset($this->pagedata[$i]['items'][$j]['data'][$k]['multiple_language_values'])) {
                            foreach ($this->pagedata[$i]['items'][$j]['data'][$k]['multiple_language_values'] as $language_code => $multiple_language_value) {
                                $plid = $page_list_item_data->replicate();
                                $plid->value = $multiple_language_value;
                                $plid->language = $language_code;
                                $plid->save();
                            }
                        }

                        // multiple_language_values

                        if ($page_list_item_data->save() === false) {
                            return false;
                        }
                        $this->pagedata[$i]['items'][$j]['data'][$k]['id'] = $page_list_item_data->id;
                    }
                } //-end of loop throught list item data
            } //-end of loop throught list items
        } //-end of loop throught lists
        return true;
    }

    /**
     * Pagedata::get()
     * The function to retrieve pagedata
     * @param int $page_id - page id of the pagedata you wish to retrieve
     * @param int $page_list_id - page list id of the pagedata you wish to retrieve
     * @param int $page_list_item_id - page list item id of the pagedata you wish to retrieve
     * @param int $page_list_item_data_id - page list item data id of the pagedata you wish to retrieve
     * @param bool $complete_with_populated_data - if pagedata should be populated
     * @param bool $detached_for_copying = false - if pagedata should be detached from page and ready for a copy/paste
     * @param array $page_list_ids to get only some of the page
     * @return bool $success
     */
    public function get(
        $page_id = 0,
        $page_list_id = 0,
        $page_list_item_id = 0,
        $page_list_item_data_id = 0,
        $complete_with_populated_data = true,
        $detached_for_copying = false,
        $page_list_ids = []
    ) {

        $this->pagedata = array();

        if (!empty($page_id) && is_numeric($page_id)) {
            $this->page_id = $page_id;

            $pl_builder = PageList::where("page_id", $page_id);

            //Restricted set of page page_lists only.
            if (!empty($page_list_ids)) {
                $pl_builder->whereIn('id', $page_list_ids);
            }

            $pl_list = $pl_builder->orderBy('order')->get();

            $i = 0;
            foreach ($pl_list as $pl) {

                //Check if list is to be used or discarded.
                $parsed_page_list = $this->parseGetPageList(
                    $pl,
                    $detached_for_copying,
                    $complete_with_populated_data,
                    false
                );
                if (empty($parsed_page_list)) {
                    continue;
                }
                $this->pagedata[$i] = $parsed_page_list;

                $pli_list = PageListItem::where("page_list_id", $pl->id)->orderBy("order")->get();
                $j = 0;
                foreach ($pli_list as $pli) {

                    $this->pagedata[$i]['items'][$j] = $this->parseGetPageListItem(
                        $pli, $detached_for_copying
                    );

                    // native cms2 multilang support
                    // by Rihards Silins
                    // 13/02/2014
                    if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true && !empty($this->language)) {
                        $plid_list = PageListItemData::getMultiLanguageList($pli->id, $this->language);
                    } else {
                        $plid_list = PageListItemData::where("page_list_item_id", $pli->id)
                            ->where("language", "")
                            ->orderBy("order")
                            ->get();
                    }

                    $k = 0;

                    foreach ($plid_list as $plid) {

                        $plid = $this->getMultipleLanguageDataValues($plid, $pli->id);

                        $this->pagedata[$i]['items'][$j]['data'][$k] =  $this->parseGetPageListItemData(
                            $plid,
                            $complete_with_populated_data,
                            $detached_for_copying
                        );
                        $k++;

                    } // data loop

                    // if not data requred - one item of list is enough
                    if (!$complete_with_populated_data) {
                        break;
                    }

                    $j++;

                } // items loop

                $i++;

            } // list loop

            return true;

        } elseif (!empty($page_list_id) && is_numeric($page_list_id)) {
            $pl = PageList::find($page_list_id);
            if (empty($pl)) {
                return false;
            }

            $this->page_id = $pl->page_id;

            $this->pagedata[0] = $this->parseGetPageList(
                $pl,
                $detached_for_copying,
                $complete_with_populated_data,
                true
            );

            $pli_list = PageListItem::where("page_list_id", $page_list_id)->orderBy("order")->get();
            $j = 0;
            foreach ($pli_list as $pli) {

                $this->pagedata[0]['items'][$j] = $this->parseGetPageListItem(
                    $pli, $detached_for_copying
                );

                // native cms2 multilang support
                // by Rihards Silins
                // 13/02/2014
                if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true && !empty($this->language)) {
                    $plid_list = PageListItemData::getMultiLanguageList($pli->id, $this->language);
                } else {
                    $plid_list = PageListItemData::where("page_list_item_id", $pli->id)
                            ->where("language", "")
                            ->orderBy("order")
                            ->get();
                }

                $k = 0;

                foreach ($plid_list as $plid) {

                    $plid = $this->getMultipleLanguageDataValues($plid, $pli->id);

                    $this->pagedata[0]['items'][$j]['data'][$k] = $this->parseGetPageListItemData(
                        $plid,
                        $complete_with_populated_data,
                        $detached_for_copying
                    );
                    $k++;
                } // data loop
                // if not data requred - one item of list is enough
                if (!$complete_with_populated_data) {
                    break;
                }
                $j++;
            } // item loop
            return true;
        } elseif (!empty($page_list_item_id) && is_numeric($page_list_item_id)) {
            $pli = PageListItem::find($page_list_item_id);
            if (empty($pli)) {
                return false;
            }

            $this->page_id = $pli->page_id;

            $this->pagedata[0] = array(
                'id'        => $pli->page_list_id,
                'page_id'   => $pli->page_id,
                'items'     => array()
            );

            if ($detached_for_copying) {
                $this->pagedata[0]['id'] = 0;
                $this->pagedata[0]['page_id'] = 0;
            }

            $this->pagedata[0]['items'][0] = $this->parseGetPageListItem(
                $pli, $detached_for_copying
            );

            // native cms2 multilang support
            // by Rihards Silins
            // 13/02/2014
            if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true && !empty($this->language)) {
                $plid_list = PageListItemData::getMultiLanguageList($pli->id, $this->language);
            } else {
                $plid_list = PageListItemData::where("page_list_item_id", $pli->id)
                    ->where("language", "")
                    ->orderBy("order")
                    ->get();
            }

            $k = 0;

            foreach ($plid_list as $plid) {

                $plid = $this->getMultipleLanguageDataValues($plid, $pli->id);

                $this->pagedata[0]['items'][0]['data'][$k] = $this->parseGetPageListItemData(
                    $plid,
                    $complete_with_populated_data,
                    $detached_for_copying
                );
                $k++;
            } // data loop
            return true;

        } elseif (!empty($page_list_item_data_id) && is_numeric($page_list_item_data_id)) {
            $plid = PageListItemData::find($page_list_item_data_id);
            if (empty($plid)) {
                return false;
            }


            $this->page_id = $plid->page_id;

            $this->pagedata[0] = array(
                'id'        => $plid->page_list_id,
                'page_id'   => $plid->page_id,
                'items'     => array()
            );

            if ($detached_for_copying) {
                $this->pagedata[0]['id'] = 0;
                $this->pagedata[0]['page_id'] = 0;

            }

            $this->pagedata[0]['items'][0] = array(
                'id'            => $plid->id,
                'page_id'       => $plid->page_id,
                'page_list_id'  => $plid->page_list_id,
                'data'          => array()
            );

            if ($detached_for_copying) {
                $this->pagedata[0]['items'][0]['id'] = 0;
                $this->pagedata[0]['items'][0]['page_id'] = 0;
                $this->pagedata[0]['items'][0]['page_list_id'] = 0;
            }

            $plid = $this->getMultipleLanguageDataValues($plid, $plid->page_list_item_id);

            $this->pagedata[0]['items'][0]['data'][0] = $this->parseGetPageListItemData(
                $plid,
                $complete_with_populated_data,
                $detached_for_copying
            );
            return true;

        }
        return false;
    }

    /**
     * Pagedata::getMultipleLanguageDataValues
     * Get multiple_language_values value of a page list item data
     * @param PageListItemData Object $page_list_item_data
     * @param int $page_list_item_id
     * @return PageListItemData Object $page_list_item_data
     */
    private function getMultipleLanguageDataValues($page_list_item_data, $page_list_item_id) {
        if (!defined('CMS_MULTI_LANG') || CMS_MULTI_LANG !== true ||
            !defined('CMS_PAGEDATA_MULTI_LANG_HANDLING') || CMS_PAGEDATA_MULTI_LANG_HANDLING !== true) {
            return $page_list_item_data;
        }
        $page_list_item_data_in_generated_languages = PageListItemData::where("page_list_item_id", $page_list_item_id)
            ->where("name", $page_list_item_data->name)
            ->get();
        $multiple_language_values = array();
        foreach ($page_list_item_data_in_generated_languages as $page_list_item_data_in_generated_language) {
            if (empty($page_list_item_data_in_generated_language->language)) {
                continue;
            }
            $multiple_language_values[$page_list_item_data_in_generated_language->language] = $page_list_item_data_in_generated_language->value;
        }
        $page_list_item_data->multiple_language_values = $multiple_language_values;
        return $page_list_item_data;

    }

    /**
     * Pagedata::parseGetPageList
     * process page_list part of get function
     *
     * @param PageList Object $page_list_object
     * @param bool $detached_for_copying
     * @param bool $complete_with_populated_data
     * @param bool $one_only flag to distinguish between whole page and one page_list only being copied
     *
     * @return mixed[] $page_list
     */
    private function parseGetPageList($page_list_object, $detached_for_copying, $complete_with_populated_data, $one_only) {
        $result = array(
            'id'                    => $page_list_object->id,
            'page_id'               => $page_list_object->page_id,
            'name'                  => $page_list_object->name,
            'type'                  => $page_list_object->type,
            'setup'                 => $page_list_object->setup,
            'lock'                  => $page_list_object->lock,
            'info'                  => $page_list_object->info,
            'order'                 => $page_list_object->order,
            'atleast_one'           => $page_list_object->atleast_one,
            'allow_more'            => $page_list_object->allow_more,
            'allow_more_max'        => $page_list_object->allow_more_max,
            'allow_more_min'        => $page_list_object->allow_more_min,
            'add_list_item_to_top'  => $page_list_object->add_list_item_to_top,
            'more_text'             => $page_list_object->more_text,
            'settings'              => $page_list_object->settings,
            'data1'                 => $page_list_object->data1,
            'data2'                 => $page_list_object->data2,
            'data3'                 => $page_list_object->data3,
            'items'                 => array()
        );
        if ($detached_for_copying) {
            $result['id'] = 0;
            $result['page_id'] = 0;
        }

        $params = [
            $page_list_object,
            &$result,
            $detached_for_copying,
            $complete_with_populated_data,
        ];
        if ($one_only) {
            $params[] = &$this;
        }

        HooksAdapter::do_action_ref_array(__CLASS__ . '/' . __FUNCTION__, [$params]);

        return $result;
    }

    /**
     * Pagedata::parseGetPageListItem
     * process page_list_item part of get function
     * @param PageListItem Object $page_list_item_object
     * @param bool $detached_for_copying
     * @return mixed[] $page_list_item
     */
    private function parseGetPageListItem($page_list_item_object, $detached_for_copying) {
        $result = array(
            'id'            => $page_list_item_object->id,
            'page_id'       => $page_list_item_object->page_id,
            'page_list_id'  => $page_list_item_object->page_list_id,
            'type'          => $page_list_item_object->type,
            'order'         => $page_list_item_object->order,
            'data1'         => $page_list_item_object->data1,
            'data'          => array()
        );
        if ($detached_for_copying) {
            $result['id'] = 0;
            $result['page_id'] = 0;
            $result['page_list_id'] = 0;
        }
        return $result;
    }

    /**
     * Pagedata::parseGetPageListItemData
     * process page_list_item_data part of get function
     * @param PageListItemData Object $page_list_item_data_object
     * @param bool $complete_with_populated_data complete with populated data
     * @param bool $detached_for_copying  detached for copying
     * @return mixed[] $page_list_item_data
     */
    private function parseGetPageListItemData($page_list_item_data_object, $complete_with_populated_data, $detached_for_copying) {
        $result = array(
            'id'                        => $page_list_item_data_object->id,
            'page_id'                   => $page_list_item_data_object->page_id,
            'page_list_id'              => $page_list_item_data_object->page_list_id,
            'page_list_item_id'         => $page_list_item_data_object->page_list_item_id,
            'name'                      => $page_list_item_data_object->name,
            'info'                      => $page_list_item_data_object->info,
            'order'                     => $page_list_item_data_object->order,
            'type'                      => $page_list_item_data_object->type,
            'setup'                     => $page_list_item_data_object->setup,
            'lock'                      => $page_list_item_data_object->lock,
            'value'                     => $page_list_item_data_object->value,
            'regex'                     => $page_list_item_data_object->regex,
            'mime'                      => $page_list_item_data_object->mime,
            'required'                  => $page_list_item_data_object->required,
            'settings'                  => $page_list_item_data_object->settings,
            'css_class'                 => $page_list_item_data_object->css_class,
            'options'                   => $page_list_item_data_object->options,
            'language'                  => $page_list_item_data_object->language,
            'uuid'                      => $page_list_item_data_object->uuid,
            'data1'                     => $page_list_item_data_object->data1,
            'data2'                     => $page_list_item_data_object->data2,
            'data3'                     => $page_list_item_data_object->data3
        );

        if (isset($page_list_item_data_object->multiple_language_values)) {
            $result['multiple_language_values'] = $page_list_item_data_object->multiple_language_values;
        }

        if (!$complete_with_populated_data) {
            unset($result['value']);
        }
        if ($detached_for_copying) {
            $result['id'] = 0;
            $result['page_id'] = 0;
            $result['page_list_id'] = 0;
            $result['page_list_item_id'] = 0;
        }

        $params = [
            &$result,
            $detached_for_copying,
            $complete_with_populated_data,
        ];
        HooksAdapter::do_action_ref_array(__CLASS__ . '/' . __FUNCTION__, [$params]);

        return $result;
    }

    /**
     * Pagedata::getExistingPagedataNames()
     * Get all the existing pagedata names that exist in the current page_list_item_data table
     * @param string $like_name optional like param
     * @return mixed[] $pagedata_names
     */
    public static function getExistingPagedataNames($like_name = "") {
        $pagedata_names = array();
        $lister = PageListItemData::orderBy("name")
            ->groupBy("name");

        if (!empty($like_name)) {
            $lister = $lister->where("name", "LIKE", "%".$like_name."%");
        }

        $page_list_item_data_list = $lister->get();
        foreach ($page_list_item_data_list as $key => $pagedata) {
            $pagedata_names[] = array(
                'name' => $pagedata->name
            );
        }
        return $pagedata_names;
    }

    public static function convertToPagedataTags( $pagedata_tree) {
        $pagedata = array();
        foreach ($pagedata_tree as $list) {
            // If this list allows mor items or has an item with several data/fields - show it as a list
            if ($list['allow_more'] == 1 || count($list['items'][key($list['items'])]['data'] ?? []) > 1 || count($list['items']) > 1) {
                $pagedata[ $list['name'] ] = array();
                foreach ($list['items'] as $key => $item) {
                    $pd_item = array();
                    foreach ($item['data'] as $key => $data) {
                        $pd_item[ $data['name'] ]['value'] = $data['value'];
                        $pd_item[ $data['name'] ]['type'] = $data['type'];
                        $pd_item[ $data['name'] ]['id'] = $data['id'];
                        $pd_item[$data['name']]['alt'] = $data['data2'];
                        // if there is only one data per item - i will allow access
                        // $p->pagedata['LIST NAME'][$i]['value']
                        if (count($item['data']) == 1) {
                            $pd_item['value'] = $data['value'];
                            $pd_item['type'] = $data['type'];
                            $pd_item['id'] = $data['id'];
                            $pd_item['alt'] = $data['data2'];
                        }
                    }
                    // $p->pagedata['LIST NAME'][$i]['DATA NAME']['value']
                    $pagedata[ $list['name'] ][] = $pd_item;
                }
            } else {
                foreach ($list['items'] as $item) {
                    foreach ($item['data'] as $data) {
                        // in this instant data and list name should be the same
                        // $p->pagedata['LIST NAME/DATA NAME'][$i]['value']
                        $pagedata[ $data['name'] ][] = array(
                            'value' => $data['value'],
                            'type' => $data['type'],
                            'id' => $data['id'],
                            'alt' => $data['data2'],
                        );
                    }
                }
            }
        }
        return $pagedata;
    }

    /**
     * Pagedata::retrievePagePagedataList()
     *
     * @return pagedata[]
     *
     * Retrieves the pagedata of page in a TREE mmade for page class displaying/printing
     */
    public static function retrievePagePagedataList( $page_id) {
        $pd = new Pagedata();

        $pd->get($page_id);

        $tree = $pd->pagedata;


        $pagedata = array();

        foreach ($tree as $list) {
            // If this list allows mor items or has an item with several data/fields - show it as a list
            if ($list['allow_more'] == 1 || count($list['items'][key($list['items'])]['data']) > 1 || count($list['items']) > 1) {
                $pagedata[ $list['name'] ] = array();
                foreach ($list['items'] as $key => $item) {
                    $pd_item = array();

                    foreach ($item['data'] as $key => $data) {
                        $pd_item[ $data['name'] ]['value'] = $data['value'];
                        $pd_item[ $data['name'] ]['type'] = $data['type'];
                        $pd_item[ $data['name'] ]['id'] = $data['id'];
                        // if there is only one data per item - i will allow access
                        // $p->pagedata['LIST NAME'][$i]['value']
                        if (count($item['data']) == 1) {
                            $pd_item['value'] = $data['value'];
                            $pd_item['type'] = $data['type'];
                            $pd_item['id'] = $data['id'];
                        }

                    }
                    // $p->pagedata['LIST NAME'][$i]['DATA NAME']['value']
                    $pagedata[ $list['name'] ][] = $pd_item;
                }
            } else {
                foreach ($list['items'] as $item) {
                    foreach ($item['data'] as $data) {
                        // in this instant data and list name should be the same
                        // $p->pagedata['LIST NAME/DATA NAME'][$i]['value']
                        $pagedata[ $data['name'] ][] = array(
                            'value' => $data['value'],
                            'type' => $data['type'],
                            'id' => $data['id']
                        );
                    }

                }

            }

        }

        return $pagedata;
    }

    public static function quickNew($page_id, $name, $value="", $type="text", $settings=array()) {
        $pd = new Pagedata();
        $pd->page_id = $page_id;
        $pd->pagedata = array(
            0 => array(
                'name' => $name,
                'items' => array(
                    0 => array(
                        'data' => array(
                            0 => array(
                                'name' => $name,
                                'type' => $type,
                                'value' => $value,
                            ),
                        )
                    ),
                )
            ),
        );

           return $pd->save();
    }

    public static function addMoreItems($request, $page) {
        $pd_copy = new Pagedata();
        $pd_copy->page_id = $page->id;
        $result = $pd_copy->get(
            0,
            $request['action_more'],
            0,
            0,
            true,
            true
        );
        if ($result === false) {
            return false;
        }

        $item = end($pd_copy->pagedata[0]['items']); // get last item

        // check if we neeed to clean this item from value
        if (!isset($request['copy_content']) || isset($request['copy_content']) && $request['copy_content'] != "1") {
            for ($i=0; $i<count($item['data']); $i++) {
                $item['data'][$i]['value'] = "";
            }
        }

        // check if we need to add item to the top of the list
        if (isset($pd_copy->pagedata[0]['add_list_item_to_top']) && $pd_copy->pagedata[0]['add_list_item_to_top'] == '1') {
            $item['order'] = 0;
        } else {
            $item['order']++;
        }

        $pd_real = new Pagedata();
        $pd_real->page_id = $page->id;
        $result = $pd_real->get(
            0,
            $request['action_more']
        );

        if ($result === false) {
            return false;
        }

        $pd_real->pagedata[0]['items'][] = $item;

        // check if we need to add item to the top of the list
        if (isset($pd_copy->pagedata[0]['add_list_item_to_top']) && $pd_copy->pagedata[0]['add_list_item_to_top'] == '1') {
            // get the key of last item that was added
            $last_item = end(array_keys($pd_real->pagedata[0]['items']));
            if (sizeof($pd_real->pagedata[0]['items']) > 0) {
                foreach ($pd_real->pagedata[0]['items'] as $key => $item) {
                    // only update order for existing items
                    // ignoring the last item that was added
                    if ($key != $last_item) {
                        $pd_real->pagedata[0]['items'][$key]['order'] = $item['order'] + 1;
                    }
                }
            }
        }

        return $pd_real->save();
    }

    public static function deleteItem($request, $page, $premission_to_delete_all) {
        if (!empty( $request['action_delete_item'] ) && !empty( $request['list_id'] )) {
            // check if i have premission to delete even the last item of a list
            if (!$premission_to_delete_all) {
                $items_in_list = PageListItem::where("page_id", $page->id)->where("page_list_id", $request['list_id'])->get(["id"]);

                $list = PageList::find($request['list_id'], ["atleast_one"]);

                // check the count and the check if the item_atleast_one is true (needs to be atleast one)

                if ($items_in_list->count() == 1 && $list->atleast_one == 1) {
                    return false;
                }

            }

            PageListItem::destroy($request['action_delete_item']);
            return true;

        }
    }

    public static function moveItem($request, $page, $direction) {
        if (!empty( $request['action_move_item'] ) && !empty( $request['list_id'] )) {
            // check if item exists
            $item = PageListItem::find($request['action_move_item']);
            if (empty($item)) {
                return false;
            }

            // check direction

            if ($direction == "up" || $direction == "move_up") {
                $item_above = PageListItem::where("page_id", $page->id)
                    ->where("page_list_id", $request['list_id'])
                    ->where("order", "<=", $item->order)
                    ->where("id", "!=", $item->id)
                    ->orderBy("order", "DESC")
                    ->first(["id", "order"]);
                if (!empty($item_above)) {

                    if ($item->order ==  $item_above->order){
                        $item_above->order--;
                        $item->order++;
                    }

                    $item_above_order = $item_above->order;
                    $item_order = $item->order;

                    $item->order = $item_above_order;
                    $item->save();

                    $item_above->order = $item_order;
                    $item_above->save();

                }

                return true;

            } elseif ($direction == "down" || $direction == "move_down") {
                $item_below = PageListItem::where("page_id", $page->id)
                    ->where("page_list_id", $request['list_id'])
                    ->where("order", ">=", $item->order)
                    ->where("id", "!=", $item->id)
                    ->orderBy("order")
                    ->first(["id", "order"]);
                if (!empty($item_below)) {

                    if ($item->order ==  $item_below->order ){
                        $item_below->order++;
                        $item->order--;
                    }

                    $item_below_order = $item_below->order;
                    $item_order = $item->order;

                    $item->order = $item_below_order;
                    $item->save();


                    $item_below->order = $item_order;
                    $item_below->save();

                }
                return true;
            }
        }
        return false;
    }

    /**
     * Pagedata::orderFix($page_id)
     *
     * Function that should be called after reorders, deletions and additions.
     *     Fixes order values so that it has no gaps.
     *
     * @param int $page_id
     * @return bool $result
     *
     */
    public static function orderFix($page_id) {
        $pd = new Pagedata();
        if ($pd->get($page_id) === false) {
            return false;
        }
        for ($i=0; $i<count($pd->pagedata); $i++) {
            $pd->pagedata[$i]['order'] = $i;
            for ($j=0; $j<count($pd->pagedata[$i]['items']); $j++) {
                $pd->pagedata[$i]['items'][$j]['order'] = $j;
                for ($k=0; $k<count($pd->pagedata[$i]['items'][$j]['data']); $k++) {
                    $pd->pagedata[$i]['items'][$j]['data'][$k]['order'] = $k;
                }
            }
        }
        return $pd->save();
    }

    /**
     * Merges pagedata with existing pagedata in object.
     * Merging means writing over pagedata structure with matching names but keeping the values
     * unless values are specified in the new structure.
     * @param mixed[][][] $new_pagedata
     * @return bool $success
     */
    public function merge($new_pagedata, $delete_pagedata_that_doesnt_exist_in_new_pagedata = true) {
        // loop through pagedata lists
        $number_of_lists = count($this->pagedata);
        for ($i=0; $i < $number_of_lists; $i++) {

            // check if the pagedata list exists in the new passed pagedata
            // if so - it requires merging

            $this_list_exists_in_the_new_pagedata = false;
            foreach ($new_pagedata as $new_index => $new_list) {
                if (!empty($new_list['name']) && $new_list['name'] === $this->pagedata[$i]['name']) {
                    $this_list_exists_in_the_new_pagedata = true;
                    $new_list_index = $new_index;
                    break;
                }
            }

            if (!$this_list_exists_in_the_new_pagedata) {
                // if it doesn't - just skip to next list (or delete?)
                if ($delete_pagedata_that_doesnt_exist_in_new_pagedata) {
                    PageList::destroy($this->pagedata[$i]['id']);
                }
                unset($this->pagedata[$i]);
                continue;
            }

            $check_vars_for_isset = [
                "type",
                "info",
                "settings",
                "data1",
                "data2",
                "data3"
            ];

            foreach ($check_vars_for_isset as $var_name) {
                if (isset($new_pagedata[$new_list_index][$var_name])) {
                    $this->pagedata[$i][$var_name] = $new_pagedata[$new_list_index][$var_name];
                }
            }

            $check_vars_for_isset_and_is_numberic = [
                "setup",
                "lock",
                "order",
                "atleast_one",
                "allow_more",
                "allow_more_max",
                "allow_more_min",
                "add_list_item_to_top"
            ];
            foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                if (isset($new_pagedata[$new_list_index][$var_name]) && is_numeric($new_pagedata[$new_list_index][$var_name])) {
                    $this->pagedata[$i][$var_name] = $new_pagedata[$new_list_index][$var_name];
                }
            }

            if (isset($new_pagedata[$new_list_index]['more_text']) && !empty($new_pagedata[$new_list_index]['more_text'])) {
                $this->pagedata[$i][$var_name] = $new_pagedata[$new_list_index]['more_text'];
            }

            for ($j=0; $j < count($this->pagedata[$i]['items']); $j++) {

                $check_vars_for_isset = [
                    "type",
                    "data1",
                ];
                foreach ($check_vars_for_isset as $var_name) {
                    if (isset($new_pagedata[$new_list_index]['items'][0][$var_name])) {
                        $this->pagedata[$i]['items'][$j][$var_name] = $new_pagedata[$new_list_index]['items'][0][$var_name];
                    }
                }

                if (isset($new_pagedata[$new_list_index]['items'][0]['order']) && is_numeric($new_pagedata[$new_list_index]['items'][0]['order'])) {
                    $this->pagedata[$i]['items'][$j]['order'] = $new_pagedata[$new_list_index]['items'][0]['order'];
                }

                $number_of_data = count($this->pagedata[$i]['items'][$j]['data']);
                for ($k=0; $k < $number_of_data; $k++) {

                    $this_data_exists_in_the_new_pagedata = false;
                    foreach ($new_pagedata[$new_list_index]['items'][0]['data'] as $new_index => $new_data) {
                        if (!empty($new_data['name']) && $new_data['name'] === $this->pagedata[$i]['items'][$j]['data'][$k]['name']) {
                            $this_data_exists_in_the_new_pagedata = true;
                            $new_data_index = $new_index;
                            break;
                        }
                    }
                    if (!$this_data_exists_in_the_new_pagedata) {
                        // if it doesn't - just skip to next data (or delete?)
                        if ($delete_pagedata_that_doesnt_exist_in_new_pagedata) {
                            PageListItemData::destroy($this->pagedata[$i]['items'][$j]['data'][$k]['id']);
                        }
                        unset($this->pagedata[$i]['items'][$j]['data'][$k]);
                        continue;
                    }

                    $check_vars_for_isset = [
                        "info",
                        "regex",
                        "mime",
                        "settings",
                        "css_class",
                        "options",
                        "language",
                        "uuid",
                        "data1",
                        "data2",
                        "data3",
                    ];
                    foreach ($check_vars_for_isset as $var_name) {
                        if (isset($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index][$var_name])) {
                            $this->pagedata[$i]['items'][$j]['data'][$k][$var_name] = $new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index][$var_name];
                        }
                    }

                    if (isset($new_pagedata[$new_list_index]['items'][$j]['data'][$new_data_index]['value'])) {
                        $this->pagedata[$i]['items'][$j]['data'][$k]['value'] = $new_pagedata[$new_list_index]['items'][$j]['data'][$new_data_index]['value'];
                    }

                    $check_vars_for_isset_and_is_numberic = [
                        "setup",
                        "lock",
                        "order",
                        "required"
                    ];
                    foreach ($check_vars_for_isset_and_is_numberic as $var_name) {
                        if (
                            isset($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index][$var_name]) &&
                            is_numeric($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index][$var_name])
                        ) {
                            $this->pagedata[$i]['items'][$j]['data'][$k][$var_name] = $new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index][$var_name];
                        }
                    }

                    if (
                        isset($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index]['type']) &&
                        !empty($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index]['type'])
                    ) {
                        $this->pagedata[$i]['items'][$j]['data'][$k]['type'] = $new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index]['type'];
                    }
                }
            }

            // add in any extra items
            for ($j=0; $j < count($new_pagedata[$new_list_index]['items']); $j++) {
                // if such item exists - skip
                if (isset($this->pagedata[$i]['items'][$j])) {
                    continue;
                }
                $this->pagedata[$i]['items'][$j] = $new_pagedata[$new_list_index]['items'][0];
                $this->pagedata[$i]['items'][$j]['order'] = $j;

                $number_of_data = count($this->pagedata[$i]['items'][$j]['data']);
                for ($k=0; $k < $number_of_data; $k++) {
                    $check_vars_for_isset = [
                        "value",
                        "data2",
                    ];
                    foreach ($check_vars_for_isset as $var_name) {
                        if (isset($new_pagedata[$new_list_index]['items'][$j]['data'][$new_data_index][$var_name])) {
                            $this->pagedata[$i]['items'][$j]['data'][$k][$var_name] = $new_pagedata[$new_list_index]['items'][$j]['data'][$new_data_index][$var_name];
                        }
                    }
                }
            }

            // sync over the data that is new
            for ($j=0; $j < count($this->pagedata[$i]['items']); $j++) {
                $number_of_data = count($this->pagedata[$i]['items'][$j]['data']);
                for ($k=0; $k < $number_of_data; $k++) {
                    $this_data_exists_in_the_new_pagedata = false;
                    foreach ($new_pagedata[$new_list_index]['items'][0]['data'] as $new_index => $new_data) {
                        if (!empty($new_data['name']) && $new_data['name'] === $this->pagedata[$i]['items'][$j]['data'][$k]['name']) {
                            $this_data_exists_in_the_new_pagedata = true;
                            $new_data_index = $new_index;
                            break;
                        }
                    }
                    if (!$this_data_exists_in_the_new_pagedata) {
                        continue;
                    }
                    unset($new_pagedata[$new_list_index]['items'][0]['data'][$new_data_index]);
                }
                $this->pagedata[$i]['items'][$j]['data'] = array_merge(
                    $this->pagedata[$i]['items'][$j]['data'],
                    $new_pagedata[$new_list_index]['items'][0]['data']
                );
            }

            unset($new_pagedata[$new_list_index]);
        }
        $this->pagedata = array_merge($this->pagedata, $new_pagedata);

        return true;
    }

    /**
     * Remove default data from a pagedata structure
     * @param mixed[][][] $pagedata
     * @return mixed[][][] $pagedata
     */
    public static function removeDefaultData($pagedata) {
        // get default structure from newly created models
        $fresh_list = PageList::create()->fresh();
        $fresh_list_item = PageListItem::create()->fresh();
        $fresh_list_item_data = PageListItemData::create()->fresh();

        foreach ($pagedata as $list_key => $list) {
            // loop through attributes compare if they are "default"
            foreach ($list as $attribute => $value) {
                if ($attribute === "id" && $value == 0 || $fresh_list->{$attribute} == $value && $attribute !== "order") {
                    // if they are - unset
                    unset($pagedata[$list_key][$attribute]);
                }
            }

            foreach ($list['items'] as $item_key => $item) {
                // loop through attributes compare if they are "default"
                foreach ($item as $attribute => $value) {
                    if ($attribute === "id" && $value == 0 || $fresh_list_item->{$attribute} == $value && $attribute !== "order") {
                        // if they are - unset
                        unset($pagedata[$list_key]['items'][$item_key][$attribute]);
                    }
                }

                foreach ($item['data'] as $data_key => $data) {
                    // loop through attributes compare if they are "default"
                    foreach ($data as $attribute => $value) {
                        if ($attribute === "id" && $value == 0 || $fresh_list_item_data->{$attribute} == $value && $attribute !== "order") {
                            // if they are - unset
                            unset($pagedata[$list_key]['items'][$item_key]['data'][$data_key][$attribute]);
                        }
                    }

                }
            }
        }

        // clean up and delete newly created models
        $fresh_list->delete();
        $fresh_list_item->delete();
        $fresh_list_item_data->delete();

        return $pagedata;
    }

    /**
     * Delete pagedata of the page
     * @param int $page_id (optional)
     * @return bool success
     */
    public function delete($page_id = null) {
        if ((empty($page_id) || !is_numeric($page_id)) && empty($this->page_id)) {
            return false;
        }
        if (!empty($page_id) && is_numeric($page_id)) {
            $this->page_id = $page_id;
        }
        $page_list_list = PageList::where("page_id", $this->page_id)
            ->get();
        foreach ($page_list_list as $page_list) {
            $page_list->delete();
        }
        return true;
    }

    /**
     * Drop orphaned pagedata
     * @return mixed[][] $result
     */
    public static function dropOrphanedPagedata() {
        $result = [
            'dropped_page_list_item_datas'  => [],
            'dropped_page_list_items'       => [],
            'dropped_page_lists'            => []
        ];
        $orphaned_page_list_item_datas = PageListItemData::query()
            ->whereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `pages` as `pages_temp`
                    WHERE `id` = `page_list_item_data`.`page_id`
                )
            ")
            ->orWhereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `page_list` as `page_list_temp`
                    WHERE `id` = `page_list_item_data`.`page_list_id`
                )
            ")
            ->orWhereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `page_list_item` as `page_list_item_temp`
                    WHERE `id` = `page_list_item_data`.`page_list_item_id`
                )
            ")
            ->get();
        foreach ($orphaned_page_list_item_datas as $orphaned_page_list_item_data) {
            $orphaned_page_list_item_data->delete();
        }
        $result['dropped_page_list_item_datas'] = $orphaned_page_list_item_datas;

        $orphaned_page_list_items = PageListItem::query()
            ->whereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `pages` as `pages_temp`
                    WHERE `id` = `page_list_item`.`page_id`
                )
            ")
            ->orWhereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `page_list` as `page_list_temp`
                    WHERE `id` = `page_list_item`.`page_list_id`
                )
            ")
            ->get();
        foreach ($orphaned_page_list_items as $orphaned_page_list_item) {
            $orphaned_page_list_item->delete();
        }
        $result['dropped_page_list_items'] = $orphaned_page_list_items;

        $orphaned_page_lists = PageList::query()
            ->whereRaw("
                NOT EXISTS (
                    SELECT `id`
                    FROM `pages` as `pages_temp`
                    WHERE `id` = `page_list`.`page_id`
                )
            ")
            ->get();
        foreach ($orphaned_page_lists as $orphaned_page_list) {
            $orphaned_page_list->delete();
        }
        $result['dropped_page_lists'] = $orphaned_page_lists;

        return $result;
    }
}
