<?php
#BEGIN_LICENSE
#-------------------------------------------------------------------------
# Module: CGClienttickets (c) 2014 by Robert Campbell
#         (calguy1000@cmsmadesimple.org)
#  An addon module for CMS Made Simple to allow interaction with customer
#  or admin created tickets about a specific data item.
#
#-------------------------------------------------------------------------
# CMS - CMS Made Simple is (c) 2005 by Ted Kulp (wishy@cmsmadesimple.org)
# This projects homepage is: http://www.cmsmadesimple.org
#
#-------------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# However, as a special exception to the GPL, this software is distributed
# as an addon module to CMS Made Simple.  You may not use this software
# in any Non GPL version of CMS Made simple, or in any version of CMS
# Made simple that does not indicate clearly and obviously in its admin
# section that the site was built with CMS Made simple.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Or read it online: http://www.gnu.org/licenses/licenses.html#GPL
#
#-------------------------------------------------------------------------
#END_LICENSE

namespace CGClientTickets;

class ticket extends DataObject
{
    static private $_persist_actor;
    const STATUS_OPEN = '_open';
    const STATUS_CLOSED = '_closed';
    const STATUS_EXPIRED = '_expired';
    const PRIORITY_HIGH = '0_high';
    const PRIORITY_NORMAL = '1_normal';
    const PRIORITY_LOW = '2_low';

    private $_data = array('id'=>null,'owner'=>null,'alert_group'=>null,'status'=>self::STATUS_OPEN,'priority'=>self::PRIORITY_NORMAL,'e_key1'=>null,'e_key2'=>null,'e_key3'=>null,'extra'=>null,'created'=>null,'modified'=>null);
    private $_dirty;

    public function __get($key)
    {
        switch( $key ) {
        case 'id':
        case 'owner':
        case 'alert_group':
        case 'status':
        case 'priority':
        case 'e_key1':
        case 'e_key2':
        case 'e_key3':
        case 'created':
        case 'modified':
            return $this->_data[$key];

        case 'extra':
            return serialize($this->_data[$key]);

        default:
            throw new \LogicException($key.' is an invalid member of '.__CLASS__);
        }
    }

    public function __set($key,$val)
    {
        switch( $key ) {
        case 'owner':
            $val = (int) $val;
            if( $val < 1 ) throw new \RuntimeException('Owner must be a valid FEU uid');
            $this->_data[$key] = $val;
            $this->_dirty = TRUE;
            break;

        case 'alert_group':
            $val = (int) $val;
            if( $val > 0 ) throw new \RuntimeException('alert group must be an admin group id represented as a negative value.');
            $this->_data[$key] = $val;
            $this->_dirty = TRUE;
            break;

        case 'status':
            switch( $val ) {
            case self::STATUS_OPEN:
            case self::STATUS_CLOSED:
            case self::STATUS_EXPIRED:
                $this->_data[$key] = $val;
                $this->_dirty = TRUE;
                break;

            default:
                throw new \RuntimeException($val.' is not a valid status for a '.__CLASS__);
            }
            break;

        case 'priority':
            switch( $val ) {
            case self::PRIORITY_HIGH:
            case self::PRIORITY_NORMAL:
            case self::PRIORITY_LOW:
                $this->_data[$key] = $val;
                $this->_dirty = TRUE;
                break;

            default:
                throw new \RuntimeException($val.' is not a valid priority for a '.__CLASS__);
            }
            break;

        case 'e_key1':
        case 'e_key2':
        case 'e_key3':
            $val = trim($val);
            $this->_data[$key] = $val;
            $this->_dirty = TRUE;
            break;

        case 'extra':
            $this->_data[$key] = unserialize($val);
            $this->_dirty = TRUE;
            break;

        case 'id':
        case 'created':
        case 'modified':
            throw new \LogicException($key.' cannot be modified in a '.__CLASS__);

        default:
            throw new \LogicException($key.' is an invalid member of '.__CLASS__);
        }
    }

    public function __isset($key)
    {
        switch( $key ) {
        case 'id':
        case 'owner':
        case 'admin_group':
        case 'status':
        case 'priority':
        case 'e_key1':
        case 'e_key2':
        case 'e_key3':
        case 'created':
        case 'modified':
            return isset($this->_data[$key]);

        default:
            throw new \LogicException($key.' is an invalid member of '.__CLASS__);
        }
    }

    public function __unset($key)
    {
        switch( $key ) {
        case 'owner':
        case 'admin_group':
        case 'e_key1':
        case 'e_key2':
        case 'e_key3':
            $this->_data[$key] = null;
            $this->_dirty = TRUE;
            break;

        case 'status':
        case 'priority':
        case 'id':
        case 'created':
        case 'modified':
            throw new \LogicException('Cannot unset member '.$key.' in a '.__CLASS__);

        default:
            throw new \LogicException($key.' is an invalid member of '.__CLASS__);
        }
    }

    public static function get_persist_actor()
    {
        return self::$_persist_actor;
    }

    public static function set_persist_actor(Actor\PersistActor $actor)
    {
        self::$_persist_actor = $actor;
    }

    public function private_fill($data)
    {
        foreach( $data as $key => $val ) {
            if( array_key_exists($key,$this->_data) ) {
                switch( $key ) {
                case 'extra':
                    $val = unserialize($val);
                default:
                    $this->_data[$key] = $val;
                }
            }
        }
    }

    public function get_dataref()
    {
        if( !$this->e_key1 ) return;
        $dr = new \CGExtensions\LinkDefinition\DataRef;

        $dr->key1 = $this->e_key1;
        $dr->key2 = $this->e_key2;
        $dr->key3 = $this->e_key3;
        return $dr;
    }

    public function get_linkdefinition()
    {
        $dr = $this->get_dataref();
        if( !is_object($dr) ) return;

        try {
            $factory = new \CGExtensions\LinkDefinition\LinkDefinitionGeneratorFactory();
            $generator = $factory->get_generator($dr);
            $ld = $generator->get_linkdefinition();
            return $ld;
        }
        catch( \Exception $e ) {
            audit('','CGClientTickets','Could not retrieve link definition for dataref '.$dr);
        }
    }

    //
    // I/O methods
    //

    public static function load_by_id($id)
    {
        $obj = self::get_persist_actor()->load_by_id($id);
        return $obj;
    }

    public function validate()
    {
        if( $this->owner < 1 ) throw new \CmsInvalidDataException('Validate: owner id is invalid for '.__CLASS__);
        if( $this->alert_group > 0 ) throw new \CmsInvalidDataException('Validate: alert_group is invalid for '.__CLASS__);
        $this->status = $this->status; // funky way of validating these values
        $this->priority = $this->priority;
    }

    public function save()
    {
        if( !$this->_dirty ) return;
        $this->validate();
        self::get_persist_actor()->save($this);
        $tmp = self::get_persist_actor()->get_saved_id();
        if( $this->id > 0 && $this->id != $tmp ) throw new \RuntimeException('Error: problem with saved object id');
        $this->_data['id'] = $tmp;
        $this->_dirty = FALSE;

        $mod = \cms_utils::get_module(MOD_CGCLIENTTICKETS);
        $mod->SendEvent($mod::EVENT_NEWTICKET,array('ticket'=>$this));
    }

    public function delete()
    {
        if( !$this->id ) throw new \RuntimeException('Error: Cannot delete a ticket that has not been saved');

        // send the event before deletion.
        $mod = \cms_utils::get_module(MOD_CGCLIENTTICKETS);
        $mod->SendEvent($mod::EVENT_DELETETICKET,array('ticket'=>$this));

        $db = \cge_utils::get_db();
        try {
            // ideally this should be abstracted
            $db->BeginTrans();

            // we're gonna load all of the messages for this ticket a batch at a time.
            // we load the messages instead of just using sql to delete them
            // so that the messge object can have a change to delete files (later)
            // if necessary.
            $parms = array('limit'=>50,'ticket_id'=>$this->id);
            $query = new Repository\MessageListQuery($parms);
            $rs = $query->execute();
            $totalMatches = $rs->TotalMatches();
            while( $query['offset'] < $totalMatches ) {
                // process these results
                // and delete them
                while( !$rs->EOF() ) {
                    $message = $rs->get_object();
                    $message->delete();
                    $rs->MoveNext();
                }

                $parms['offset'] = $query['offset'] + $query['limit'];
                if( $query['offset'] < $totalMatches ) break;
                $query = new MessageListQuery($parrms);
                $rs = $query->execute();
            }

            self::get_persist_actor()->delete($this);

            // all done
            $id = $this->id;
            $db->CommitTrans(); // should be abstracted too.
            $this->_data['id'] = null;
            $this->_dirty = TRUE;
        }
        catch( \Exception $e ) {
            $db->RollbackTrans();
            throw $e;
        }
    }
} // end of class

#
# EOF
#
?>
