<?php
/**
 * Base class for all controls.
 * This class implements the properties and methods shared by all controls.
 *
 * @author Ely Edison Matos [ely.matos@ufjf.edu.br]
 * 
 * @version 1.0
 *
 * \b Maintainers: \n
 * Ely Edison Matos [ely.matos@ufjf.edu.br] 
 * 
 * @see 
 * {@link MComponent}
 *
 * @since 
 * This class was created 2005/01/01
 *
 * \b Organization: \n
 * SOLIS - Cooperativa de Soluções Livres \n
 * The Miolo Development Team
 * 
 * \b CopyLeft: \n
 * CopyLeft (L) 2005 SOLIS - Cooperativa de Soluções Livres \n
 *
 * \b License: \n
 * Licensed under GPL (for further details read the COPYING file or http://www.gnu.org/copyleft/gpl.html )
 * 
 * \b History: \n
 * See history in CVS repository: http://www.miolo.org.br
 * 
 */

abstract class MControl extends MComponent
{
    /** 
     * A number used to identify anonymous controls.
     */
    static  $_number = 0;

    /** 
     * An id based in $number.
     */
    private $_numberId;

    /** 
     * A id for the control.
     * This atribute identifies the control. It is used at (X)HTML rendering.
     */
    public $id;

    /** 
     * Another id for the control.
     * This atribute identifies the control's box in (X)HTML rendering.
     */
    public $uniqueId;

    /** 
     * Indicates if the control is enabled/disabled.
     */
    public $enabled;

    /** 
     * A Style Object
     */
    public $style;

    /** 
     * A MAttributes object
     */
    public $attrs; 

    /** 
     * A string with (X)HTML attributes.
     * For compatibilty only.
     */
    public $attributes;

    /**
     * Indicates if the control is to be mantained in round-trips.
     */
    public $maintainState;

    /**
     * Show the control as a label.
     */
    public $readonly;

    /**
     * Is the control visible?
     */
    public $visible;

    /**
     * A caption for the control.
     */
    public $caption;

    /**
     * A hint showed as tooltip, using javascript.
     */
    public $jsHint;

    /**
     * A hint showed as MSpan, using HTML
     */
    public $hint;

    /** 
     * Indicates if the control is to be CSS Positioned
     */
    public $cssp;

    /**
     * The control's code according to render method.
     * The $inner is generated by the control itself, according to its properties.
     */
    public $inner;

    /**
     * The parent component (the owner of this control).
     */
    public $parent;

    /**
     * A list with registered event handlers .
     */
    public $eventHandlers;

    /**
     * The class for renderize controls.
     */
    public $painter;

    /**
     * Build handlers for javascripts events of control
     */
    public $event;

    /** 
     * The Id of MHtmlForm where this control is inserted
     * It is used to build single names of controls and ajax handlers
     */
    public $formId;

    /**
     *  Center alignment
     */
    const ALIGN_CENTER = 'center';

    /**
     * Left alignment
     */
    const ALIGN_LEFT = 'left';

    /**
     * Right alignment
     */
    const ALIGN_RIGHT = 'right';
    
    /** 
     * Define the constants to be used
     * to indicate the $formMode
     */
    const FORM_MODE_WHOLE_ROW  = 0;
    const FORM_MODE_SHOW_SIDE  = 1;
    const FORM_MODE_SHOW_ABOVE = 2;
    const FORM_MODE_SHOW_NBSP  = 3;

    /** 
     * Indicates how to render the control/caption in the page.
     * FORM_MODE_WHOLE_ROW  = 0 : the control ocuppies whole row of form
     * FORM_MODE_SHOW_SIDE  = 1 : show caption: control side by side
     * FORM_MODE_SHOW_ABOVE = 2 : show caption: above the control
     * FORM_MODE_SHOW_NBSP  = 3 : show caption:&nbsp;&nbsp;control
     */
    public $formMode;

    /**
     * Initialize some properties.
     * @param $name (string) a optional name for the control
     */
    public function __construct( $name = NULL )
    {
        parent::__construct( $name );
        $this->_numberId = MControl::$_number++;
//        $this->id        = ( ( $this->name == NULL ) ? 'm'.$this->_numberId : $this->name );
        $this->uniqueId   = $this->className.$this->_numberId;
        $this->id        = $name;
        $this->enabled   = true;
        $this->attrs     = new MAttributes();
        $this->style     = new MStyle();
        $this->maintainState = false;
        $this->readonly   = false;
        $this->cssp       = false;
        $this->visible    = true;
        $this->eventHandlers = array ( );
        $this->inner      = '';
        $this->event      = array();
        $this->formMode   = self::FORM_MODE_WHOLE_ROW;;
        $this->formId     =  ($this->page ? $this->page->getFormId() : '');
        $this->painter    = $this->manager->getPainter();
    }

    /*
        Identification
    */

    public function setName($name)
    {
        MUtil::setIfNull($this->id, $name);
        parent::setName($name);
    }

    public function setId($id)
    {
        $this->id = $id;
        MUtil::setIfNull( $this->name, $id );
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getUniqueId()
    {
        return $this->uniqueId;
    }

    /** 
     * The clone method.
     * It is used to clone controls, avoiding references to same attributes, styles and controls.
     */
    public function __clone()
    {
        $this->attrs      = clone $this->attrs; 
        $this->style      = clone $this->style; 
    }

    /*
        Facade to Style methods
    */
 
    public function __set( $name, $value )
    {
        $this->style->$name = $value;
    }

    public function __get( $name )
    {
        return $this->style->get($name);
    }

    protected function _addStyle($name, $value)
    {
        $this->style->addStyle($name, $value);
    }

    /**
     * Set class attribute to the element.
     *
     * @param string $cssClass Class name.
     * @param boolean $add Whether to add or replace (if exists) the class.
     */
    public function setClass($cssClass, $add=TRUE)
    {
        $this->style->setClass($cssClass, $add);
    }

    public function insertClass( $cssClass )
    {
        $this->style->insertClass($cssClass);
    }

    public function addStyleFile( $styleFile )
    {
        $this->style->addStyleFile($styleFile);
    }

    /**
     * @return string Get the value from class attribute.
     */
    public function getClass()
    {
        return $this->style->getClass();
    }

    public function addStyle($name, $value)
    {
        $this->style->addStyle($name, $value);
    }

    public function setStyle($style)
    {
        $this->style->setStyle($name, $value);
    }

    public function getStyle()
    {
        return $this->style->getStyle();
    }

    public function getBoxStyle()
    {
        return $this->style->getStyle();
    }

    public function setPosition($left, $top, $position = 'absolute')
    {
        $this->style->setPosition($left, $top, $position);
    }

    public function setWidth($value)
    {
        $this->style->setWidth($value);
    }

    public function setHeight($value)
    {
        $this->style->setHeight($value);
    }

    public function setColor($value)
    {
        $this->style->setColor($value);
    }

    public function setVisibility($value)
    {
        $this->style->setVisibility($value);
    }

    public function setFont($value)
    {
        $this->style->setFont($value);
    }

    /*
        Facade to Attribute methods
    */

    public function addAttribute( $name, $value = '' )
    {
        $this->attrs->addAttribute( $name, $value);
    }


    public function setAttribute( $name, $value=null )
    {
        $this->attrs->addAttribute( $name, $value);
    }

    public function getAttribute( $name )
    {
        return $this->attrs->getAttribute( $name);
    }

    public function setAttributes($attr)
    {
        $this->attrs->setAttributes( $attr );
    }

    public function attributes( $mergeDuplicates=false )
    {
        return $this->attrs->attributes( $mergeDuplicates);
    }

    public function getAttributes( $mergeDuplicates=false )
    {
        return $this->attrs->getAttributes( $mergeDuplicates) . ' '. $this->getStyle();
    }

    /*
        Flags
    */

    public function setReadOnly($status)
    {
        $this->readonly = $status;
    }

    /**
     * Enabled status.
     * Acessory method to set the enabled status of the control.
     * 
     * @param state (boolean) true or false depending the status
     */
    public function setEnabled($state)
    {
        $this->enabled = $state;
    }

    /*
        Generic Attributes
    */

    public function setJsHint( $hint )
    {
        if ( $hint != '' )
        {
            $this->jsHint = $hint;
            $this->page->addDojoRequire("dijit.Tooltip");
        }
        return;
    }

    public function setHint( $hint )
    {
        if ( $hint != '' )
        {
            $this->hint = $hint;
        }
        return;
    }

    public function setCaption($caption)
    {
        $this->caption = $caption;
    }

    public function setHTMLTitle($title)
    {
        $this->addAttribute('title',$title);
    }

    //
    //  EventHandler
    // 
    public function eventHandler()
    {
        $subject = $this;
        $form = $this->manager->formSubmit;
        $event = MIOLO::_REQUEST($form.'__EVENTTARGETVALUE');
        $args  = MIOLO::_REQUEST($form.'__EVENTARGUMENT');
        $func = null;

        if ($event == '')
        {
            $event = MIOLO::_REQUEST('__EVENTTARGETVALUE');
            $args  = MIOLO::_REQUEST('__EVENTARGUMENT');
        }
        if (($args == '') && ( $this->manager->getIsAjaxCall() ))
        {
            $args = (object)$_REQUEST;
        }
        if ($event != '')
        {
            $eventTokens = explode(':', $event);
            $sender = $subject->findControlById( $eventTokens[0] );
            $func   = str_replace(':', '_', $event);
            if ( method_exists($subject, $func) )
            {
                $subject->$func($args);
            }
            elseif ( $sender instanceof MControl )
            {
                $eventType = $eventTokens[1];
                $func      = $sender->eventHandlers[$eventType]['handler'];
                if ( ! is_null($func) )
                {
                    if ( method_exists($subject, $func) )
                    {
                        $subject->$func($args);
                    }
                    elseif ( function_exists($func) )
                    {
                        $func($args);
                    }
                }
            }
        }
        if($eventTokens = explode(';', MIOLO::_REQUEST('event')))
        {
            $e = str_replace(':', '_', $eventTokens[0]);

            if ( (strtolower($e) !== strtolower($func)) && (method_exists($subject, $e) ) )
            {
                $params = $eventTokens[1];
                $subject->$e($params);
            }
        }
    }


    public function attachEventHandler( $name, $handler, $param = NULL )
    {
        $this->eventHandlers[$name]['handler'] = $handler;
        $this->eventHandlers[$name]['param']   = $param;
    }

    public function addEvent($event, $handler, $preventDefault = true)
    {
        if ( $handler{0} == ':' )
        {
            $handler = $this->manager->getUI()->getAjax($handler);
        }
        else
        {
            if ($this->id == '') $this->id = $this->uniqueId;                
        }
        $e = array('handler'=>$handler, 'prevent'=>$preventDefault);
        $this->event[$event][] = $e;
    }

    public function hasEvent($event)
    {
        return (isset($this->event[$event]) && count($this->event[$event]) > 0);
    }

    public function generateEvent()
    {
        if ( is_array($this->event) )
        {
            foreach($this->event as $event=>$handlers)
            {
                if ($this->hasEvent($event))
                {
                    foreach($handlers as $handler)
                    {
                        $p = $handler['prevent'] ? "true" : "false";
                        $h = $handler['handler'];
                        $register = "miolo.registerEvent(\"{$this->id}\",\"{$event}\",\"{$h}\", {$p});";
                        $this->page->onLoad($register);
                    }
                }
            }  
        }
    }

    /*
        Content and rendering
    */

    public function setContent($inner)
    {
        $this->inner = $inner;
    }

    public function setInner($inner)
    {
        $this->inner = $inner;
    }

    public function getInner()
    {
        return $this->inner;
    }

    public function getRender( $method )
    {
        return $this->painter->$method( $this );
    }

    public function getInnerToString()
    {
        return $this->painter->generateToString( $this->getInner() );
    }

    public function getCSSP()
    {
        return $this->cssp || $this->style->cssp;
    }

    /*
        Must be override by descendant controls
    */
    public function generateInner()
    {
        return $this->inner;
    }

    public function generate()
    {
        $this->generateInner();
        $content = $this->getInner();

        if ( $this->jsHint != '' )
        {
            $jsHint = $this->jsHint;
            $hint = new MDiv('', '', null, "dojoType=\"dijit.Tooltip\" connectId=\"{$this->getId()}\" ");
            $hint->addAttribute("label",$jsHint);
            $content = $hint->generate() .$content;
        }

        if ( $this->hint && MBaseForm::$showHints )
        {
            $hint = new MHint($this->hint);
            $content .= $hint->generate();
        }
/*
        if ( count($this->eventHandlers) )
        {
            foreach($this->eventHandlers as $eventType=>$event)
            {
                if ( ! strncmp($eventType,'on',2) )
                {
                    $this->page->addScript('x/x_core.js');
                    $this->page->addScript('x/x_event.js');
                    $eventType = substr($eventType,2);
                    $this->page->onLoad("xAddEventListener('{$this->id}','{$eventType}' ,{$event['handler']});");
                }
            }
        }
*/
        $this->generateEvent();
        return $this->painter->generateToString($content);
    }

    public function __toString() 
    {
    	return $this->generate();
    }
    


}

class MControlConcrete extends MControl
{
}

?>
