<?php

namespace bfw\mvc\model {

    use bfw\Database;

    /**
     * Class Model
     *
     * Model besitzt einen State in $data
     *
     *
     * @method string getId()
     * @method setId($param)
     */
    class Model {
        private static $logger = null;

        protected $table;
        protected $db;

        protected $data;

        public function getData() {
            return $this->data;
        }

        /**
         * <b>Herzstück des Persistence-Frameworks</b>
         *
         * Dynamische Erzeugung von Getttern- und Settern
         *
         * Anstatt diese explizit zu pflegen und zu warten,
         * werden Diese dynamisch, on, the fly, erzeugt.
         *
         * <b>Der Vorteil: Nicht Konfigurieren, nicht Erzeugen. Einfach Nutzen...</b>
         *
         * @param $methodName
         * @param null $params
         * @return $this
         */
        public function __call($methodName, $params = null) {
            $prefix = substr($methodName, 0, 3);
            $key = strtolower(substr($methodName, 3));

            if ($prefix == 'set') {
                $value = $params[0];

                $this->data[$key] = $value;

                // fluent please!
                return $this;

            } else if ($prefix == 'get') {
                if (array_key_exists($key, $this->data)) {
                    return $this->data[$key];
                }
            }

            exit(sprintf('Unbekannte Methode %s::%s(%s, %s) wurde aufgerufen.', get_class($this), $methodName, $key, $prefix));
        }

        /**
         * @param $table
         */
        public function __construct($table) {
            self::$logger = \Logger::getLogger('__CLASS__');

            $this->db = Database::getInstance();
            $this->table = $table;
            $this->data = array();
        }

        /**
         * <b>Vereinfachte Find Methode bezogen auf die jeweilige Instanz</b>
         *
         * @param $id
         * @return Model
         */
        public function find($id) {
            self::$logger->info(sprintf('%s(%d) ', __METHOD__, $id));

            if (($this->data = $this->db->find($this->table, $id)) == null) {
                return null;
            }

            return $this;
        }

        /**
         * <b>Die Findall Methode erzeugt typsicher den Supertyp</b>
         *
         * @param bool|false $sys
         * @return Model[]
         */
        public function findAll($sys = false) {
            self::$logger->info(sprintf('%s() ', __METHOD__));

            $initial_id = ($sys) ? 0 : 1;
            $rows = $this->db->findAll($this->table, $initial_id);

            if (count($rows) == 0) {
                return array();
            }

            $list = array();
            foreach ($rows as $row) {
                $item = new static();
                $item->data = $row;

                $list[] = $item;
            }

            self::$logger->info(sprintf('%s(): %d', __METHOD__, count($list)));

            return $list;
        }

        /**
         * <b>Vereinfachte FindByField Methode</b>
         *
         * @param $field
         * @param $value
         * @return Model
         */
        public function findByField($field, $value) {
            self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));

            $this->data = $this->db->findByField($this->table, $field, $value);

            // Keine Daten, keine Instanz
            if ($this->data == null) {
                return null;
            }

            return $this;
        }

        /**
         * <b>Vereinfachte FindAllByField Methode</b>
         *
         * Erzeugt on the fly ein array mit dem Supertyp der Klasseninstanz
         * @param $field
         * @param $value
         * @return Model[]
         */
        public function findAllByField($field, $value) {
            self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));

            $rows = $this->db->findAllByField($this->table, $field, $value);

            if ($rows == null) {
                return null;
            }

            $list = array();
            foreach ($rows as $row) {
                $item = new static();
                $item->data = $row;

                $list[] = $item;
            }

            return $list;
        }

        /**
         * <b>Vereinfachte persist Methode</b>
         *
         * Der Logger loggt nur die Nutzdaten, deswegen sieht das im Log identisch aus.
         *
         * Es handelt sich allerdings einmal um ein Objekt und einmal nur um ein Array.
         *
         * @param $object
         * @return bool
         */
        public function persist($object) {
            self::$logger->info(sprintf('%s(%s)', __METHOD__, print_r($object->getData(), true)));

            return $this->db->persist($this->table, $object->getData());
        }

        /**
         * <b>Vereinfachte store Methode</b>
         *
         * @param $id
         * @param $object
         * @return bool
         */
        public function store($id, $object) {
            self::$logger->info(sprintf('%s(%d, %s)', __METHOD__, $id, print_r($object->getData(), true)));

            if ($id > 1) {
                return $this->db->store($this->table, $id, $object->getData());
            }

            return false;
        }

        /**
         * <b>Vereinfachte delete Methode</b>
         *
         * @param $id
         * @return bool
         */
        public function delete($id) {
            self::$logger->info(sprintf('%s(%d) ', __METHOD__, $id));

            if ($id > 1) {
                return $this->db->delete($this->table, $id);
            }

            return false;
        }

    }
}