<?php

namespace TdyCommons\Model;

use TdyCommons\Filter\Word\LowercaseFirst;
use Zend\Filter\FilterChain;
use Zend\Filter\Word\DashToCamelCase;
use Zend\Filter\Word\UnderscoreToCamelCase;


/**
 * Class Model
 *
 * @package TdyCommons\Model
 *
 * @author  James Lloyd Atwil <james@nadows.com>
 */
abstract class Model
{

    /**
     * Flag if the Model is active.
     *
     * @var int
     */
    public $isActive = 1;

    /**
     * Flag if the Model is part of the core, meaning do not delete.
     *
     * @var int
     */
    public $isCore = 0;

    /**
     * The date and time created.
     *
     * @var \DateTime|null
     */
    public $createdOn = null;

    /**
     * User ID created.
     *
     * @var int|null
     */
    public $createdBy = null;

    /**
     * The date and time last updated.
     *
     * @var \DateTime|null
     */
    public $updatedOn = null;

    /**
     * User ID updated last.
     *
     * @var int|null
     */
    public $updatedBy = null;

    /**
     * The date and time last deleted.
     *
     * @var \DateTime|null
     */
    public $deletedOn = null;

    /**
     * User ID deleted last.
     *
     * @var int|null
     */
    public $deletedBy = null;

    /**
     * @var array
     */
    protected $dates = [
        'birthdate',
        'createdOn',
        'updatedOn',
        'deletedOn',
        'bannedOn',
        'startsOn',
        'endsOn',
        'preparedOn',
        'generatedOn',
        'submittedOn',
        'approvedOn'
    ];

    /**
     * @var array
     */
    protected $integers = [
        'rowNo',
        'id',
        'status',
        'isActive',
        'isCore',
        'isBanned',
        'isPrepared',
        'isGenerated',
        'isSubmitted',
        'isApproved',
        'createdBy',
        'updatedBy',
        'deletedBy'
    ];

    /**
     * @var array
     */
    protected $floats = [
        'amount',
        'total'
    ];

    /**
     * Magic method for setting the values. You don't need to call it directly.
     *
     * @param string                 $name
     * @param string|int|float|array $value
     */
    public function __set($name, $value)
    {
        if (in_array($name, $this->integers)) {
            $this->$name = !is_null($name) ? (int) $value : null;
        } else {
            $this->$name = $value;
        }
    }

    /**
     * Magic method for getting the attributes. You don't need to call it directly.
     *
     * @param $name
     *
     * @return string|int|float|array
     */
    public function __get($name)
    {
        $filter = new FilterChain();
        $filter->attach(new UnderscoreToCamelCase());
        $filter->attach(new LowercaseFirst());
        $name = $filter->filter($name);

        return $this->$name;
    }

    /**
     * Set the attributes via arrays.
     *
     * @param array $data
     */
    public function exchangeArray($data)
    {

        foreach ($data as $key => $value) {
            $filter = new FilterChain();
            if (strpos($key, '-') !== false) {
                $filter->attach(new DashToCamelCase());
            } else {
                $filter->attach(new UnderscoreToCamelCase());
            }
            $filter->attach(new LowercaseFirst());
            $nKey = $filter->filter($key);

            if (!property_exists(__CLASS__, $nKey)) {
                continue;
            }

            if (in_array($nKey, $this->dates)) {
                $this->$nKey = new \DateTime($value);
            } else if (in_array($nKey, $this->integers)) {
                $this->$nKey = !is_null($value) ? (int) $value : null;
            } else if (in_array($nKey, $this->floats)) {
                $this->$nKey = !is_null($value) ? (float) $value : null;
            } else {
                $this->$nKey = $value;
            }
        }
    }

    /**
     * Returns an array of attribute values.
     *
     * @return array
     */
    public function getArrayCopy()
    {
        return get_object_vars($this);
    }


    /**
     * @return \StdClass
     */
    public function toStdClass()
    {
        $object = new \StdClass();
        foreach (get_object_vars($this) as $key => $value) {
            if ($value instanceof \DateTime) {
                $isDate = in_array($key, $this->dates);

                if ($isDate) {
                    $class = new \StdClass();

                    $class->timeStamp         = new \StdClass();
                    $class->timeStamp->short  = $value->format('M j, Y g:i a');
                    $class->timeStamp->normal = $value->format('F j, Y g:i a');
                    $class->timeStamp->iso    = $value->format('Y-m-d H:i');

                    $class->date         = new \StdClass();
                    $class->date->short  = $value->format('M j, Y');
                    $class->date->normal = $value->format('F j, Y');
                    $class->date->iso    = $value->format('Y-m-d');

                    $class->time         = new \StdClass();
                    $class->time->normal = $value->format('g:i a');
                    $class->time->iso    = $value->format('H:i');

                    $object->$key = $class;
                }
            } else {
                $object->$key = $value;
            }
        }

        if (isset($this->sex)) {
            $class     = new \StdClass();
            $this->sex = (int) $this->sex;
            switch ($this->sex) {
                case 0:
                    $class->id     = 0;
                    $class->symbol = 'm';
                    $class->name   = 'Male';
                    break;
                case 1:
                    $class->id     = 1;
                    $class->symbol = 'f';
                    $class->name   = 'Female';
                    break;
            }

            $object->sex = $class;
        }

        unset($object->dates);
        unset($object->integers);
        unset($object->floats);

        unset($object->isActive);
        unset($object->isCore);
        unset($object->createdBy);
        unset($object->createdOn);
        unset($object->updatedBy);
        unset($object->updatedOn);
        unset($object->deletedBy);
        unset($object->deletedOn);

        unset($object->sm);

        return $object;
    }

    /**
     * @return \StdClass
     */
    public function toReportClass()
    {
        $object = new \StdClass();
        foreach (get_object_vars($this) as $key => $value) {
            if ($value instanceof \DateTime) {
                $sKey   = strtolower($key);
                $isDate = strpos($sKey, 'date') !== false || ($sKey === 'validityperiod');
                $isTime = strpos($sKey, 'time') !== false;
                $isETD  = strpos($sKey, 'etd') !== false;
                $isETA  = strpos($sKey, 'eta') !== false;

                $isTimeStamp = strpos($key, 'submittedOn') !== false || strpos($key, 'preparedOn') !== false || strpos($key, 'requestedOn') !== false
                    || strpos($key,
                        'generatedOn') !== false
                    || strpos($key, 'selectedOn') !== false;

                $isBirthdate = strpos($sKey, 'birthdate') !== false;

                if ($isDate || $isBirthdate) {
                    $object->$key = $value->format('F j, Y');;
                }

                if ($isTime || $isETD || $isETA) {
                    $object->$key = $value->format('h:i a');
                }

                if ($isTimeStamp) {
                    $object->$key = $value->format('F j, Y g:i a');
                }
            } else {
                $object->$key = $value;
            }
        }

        if (isset($this->sex)) {
            $this->sex = (int) $this->sex;
            switch ($this->sex) {
                case 0:
                    $object->sex = 'Male';
                    break;
                case 1:
                    $object->sex = 'Female';
                    break;
            }
        }

        unset($object->rowNo);
        unset($object->isActive);
        unset($object->isCore);
        unset($object->createdBy);
        unset($object->createdOn);
        unset($object->updatedBy);
        unset($object->updatedOn);
        unset($object->deletedBy);
        unset($object->deletedOn);

        unset($object->sm);

        return $object;
    }

}
