<?php
/*
 *  $Id: Propel.php 1347 2009-12-03 21:06:36Z francois $
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information please see
 * <http://propel.phpdb.org>.
 */

require_once 'HTML/QuickForm.php';

define('HTML_QUICKFORM_PROPEL_NO_COLUMNS', 2);
define('HTML_QUICKFORM_PROPEL_ALL_COLUMNS', 3);
define('HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE', 4);
define('HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN', 5);

/* On large foreign table resultsets propel choked */
# ini_set('memory_limit', '50M');

/**
 *
 *  NOTE: HTML_QuickForm_Propel extends HTML_QuickForm, so all QuickForm functionality is available.
 *
 *  A fictive example:
 *
 *  $className = 'book';
 *  $id = '7'; // existing item
 *  $id = null; // when no id is passed, it's assumed we are creating a new item
 *
 *  $quickForm = new HTML_QuickForm_Propel($className, $id); // optionally pass it to the constructor
 *  $quickForm->setAction('/Bookstore/Form');
 *  $quickForm->addElement('header', '', 'HTML_QuickForm_Propel');
 *  $quickForm->setId($id);
 *  $quickForm->setClassName($className);
 *  $quickForm->setTarget('_self');
 *  $quickForm->setMethod('post');
 *
 *  // use this to override the default behaviour for
 *  // foreign table select boxes, UserPeer::UNAME will be shown in the select list.
 *  // It defaults to the first string column in the foreign table.
 *
 *  $quickForm->joinColumn(bookPeer::PUBLISHER_ID,UserPeer::UNAME);
 *
 *  // default to all columns shown
 *  $quickForm->setColumnMode(HTML_QUICKFORM_PROPEL_ALL_COLUMNS);
 *  $quickForm->hideColumn('PASS');
 *
 *  // or default to no columns shown
 *  $quickForm->setColumnMode(HTML_QUICKFORM_PROPEL_NO_COLUMNS);
 *  $quickForm->showColumn('NAME'); // column name without table prefix.
 *  $quickForm->showColumn('UNAME');
 *  $quickForm->showColumn('USER_INFO');
 *  $quickForm->showColumn('EMAIL');
 *  $quickForm->showColumn('FEMAIL');
 *  $quickForm->showColumn('URL');
 *  $quickForm->showColumn('PASS');
 *
 *  // generate the form
 *  $quickForm->build();
 *
 *  // after the form is build, it's possible to modify the generated elements
 *  $quickForm->getElement('NAME')->setSize(10); // manually tune this element
 *
 *  if ($quickForm->validate()) {
 *          $quickForm->freeze();
 *
 *          // save the object we have editted
 *          $quickForm->save();
 *  } else {
 *          $quickForm->toHtml(); // or any other QuickForm render option
 *  }
 *
 * TODO: map all creoleTypes to usefull formelements
 *
 * @author     Rob Halff <info@rhalff.com>
 *   some improvements by Zoltan Nagy (sunshine@freemail.hu)
 * @version    $Rev: 1347 $
 * @copyright  Copyright (c) 2005 Rob Halff: LGPL - See LICENCE
 * @package    propel.contrib
 */

class HTML_QuickForm_Propel extends HTML_QuickForm {

		/**
		 * ID of the Propel Object.
		 * @var        integer
		 * @access     private
		 */
		private $id;

		/**
		 * Contains column visibility information.
		 * @var        array
		 * @access     private
		 */
		private $columnVisibility = array();

		/**
		 * Contains titles of columns.
		 * @var        array
		 * @access     private
		 */
		private $columnTitle = array();

		/**
		 * The Column visibility mode either.
		 * Possible values:
		 *
		 * HTML_QUICKFORM_PROPEL_ALL_COLUMNS
		 * HTML_QUICKFORM_PROPEL_NO_COLUMNS
		 *
		 * @var        integer
		 * @access     private
		 */
		private $columnMode;

		/**
		 * String containing the peerName.
		 * @var        string
		 * @access     private
		 */
		private $peerName;

		/**
		 * String containing the className of the propel Object.
		 * @var        string
		 * @access     private
		 */
		private $className;

		/**
		 * The Column objects.
		 *
		 * @var        array
		 * @access     private
		 */
		private $cols;

		/**
		 * The Object being operated on.
		 * @var        object
		 * @access     private
		 */
		private $obj;

		/**
		 * Seperator value.
		 *
		 * In case the option list will be build by multiple values
		 * This is the value these fields will be seperated with
		 *
		 * @var        string
		 * @access     private
		 */
		private $seperator = ' ';

		/**
		 *
		 * Not used yet.
		 *
		 * @var        array
		 * @access     private
		 */
		private $joinMap = array();

		/**
		 * The default QuickForm rule type to use.
		 * Either server or client
		 *
		 * @var        string
		 * @access     private
		 */
		private $defaultRuleType = 'server';


		/**
		 * This is used in the QuickForm DateElement
		 * @var        string
		 * @access     private
		 */
		private $lang = 'en';

		/**
		 * Rulemapping should cover all available propel rules
		 *
		 * @var        array
		 * @access     private
		 */
		private $ruleMapping =  array(
						'mask'=>'regex',
						'maxLength'=>'maxlength',
						'minLength'=>'minlength',
						'maxValue'=>'maxvalue',
						'minValue'=>'minvalue',
						'required'=>'required',
						'validValues'=>'validvalues',
						'unique'=>'unique'
						);

		/**
		 *
		 * CreoleType to QuickForm element mapping
		 *
		 * @var        array
		 * @access     private
		 */
		private $typeMapping = array(
						CreoleTypes::BOOLEAN    =>'radio',
						CreoleTypes::BIGINT     =>'text',
						CreoleTypes::SMALLINT   =>'text',
						CreoleTypes::TINYINT    =>'text',
						CreoleTypes::INTEGER    =>'text',
						CreoleTypes::NUMERIC    =>'text',
						CreoleTypes::DECIMAL    =>'text',
						CreoleTypes::REAL       =>'text',
						CreoleTypes::FLOAT      =>'text',
						CreoleTypes::DOUBLE     =>'text',
						CreoleTypes::CHAR       =>'text',
						CreoleTypes::VARCHAR    =>'text',
						CreoleTypes::LONGVARCHAR=>'textarea',
						CreoleTypes::TEXT       =>'textarea',
						CreoleTypes::TIME       =>'text',
						CreoleTypes::TIMESTAMP  =>'date',
						CreoleTypes::DATE       =>'date',
						CreoleTypes::YEAR       =>'text',
						CreoleTypes::VARBINARY  =>'text',
						CreoleTypes::BLOB       =>'text',
						CreoleTypes::CLOB       =>'text',
						CreoleTypes::BINARY     =>'text',
						CreoleTypes::LONGVARBINARY=>'text',
						CreoleTypes::ARR        =>'text',
						CreoleTypes::OTHER      =>'text'
								);

		/**
		 *
		 * The Constructor
		 *
		 * Classname and id are specific to HTML_QuickForm_Propel
		 *
		 * The other parameters are needed to construct the parent QuickForm Class.
		 *
		 * @param      string className
		 * @param      string id
		 * @param      string formName
		 * @param      string method
		 * @param      string action
		 * @param      string target
		 * @param      array attributes
		 * @param      boolean trackSubmit
		 *
		 */
		public function __construct($className = null, $id = null, $formName='HTML_QuickForm_Propel', $method='post', $action='', $target='_self', $attributes=null, $trackSubmit = false)
		{
				$this->setClassName($className);
				$this->setPeerName($className.'Peer'); // Is this always true ?
				$this->setId($id);
				parent::HTML_QuickForm($formName, $method, $action, $target, $attributes, $trackSubmit);

				// set the default column policy
				$this->setColumnMode(HTML_QUICKFORM_PROPEL_ALL_COLUMNS);
		}

		/**
		 *
		 * NOT IMPLEMENTED
		 *
		 * Allows for creating complex forms.
		 * Note that limit 1 will always be added to the criteria.
		 * Because we can only edit one record/row at a time.
		 *
		 * However we will be able to join tables in complex ways.
		 *
		 * @param      Criteria
		 *
		 */
		public function setCriteria(Criteria $c)
		{
				$c->setLimit(1);
				$this->criteria = $c;
		}

		/**
		 *
		 * Set the action of this form
		 *
		 * @param      string action
		 *
		 */
		public function setAction($action)
		{
				$attributes = array('action'=>$action);
				$this->updateAttributes($attributes);
		}

		/**
		 *
		 * Set method of this form, e.g. post or get
		 *
		 * @param      string method
		 *
		 */
		public function setMethod($method)
		{
				$attributes = array('method'=>$method);
				$this->updateAttributes($attributes);
		}

		/**
		 *
		 * Set the target of this form
		 *
		 * @param      string target
		 *
		 */
		public function setTarget($target)
		{
				$attributes = array('target'=>$target);
				$this->updateAttributes($attributes);
		}

		/**
		 *
		 * Set the id of the object we need to get
		 *
		 * @param      string id
		 *
		 */
		public function setId($id)
		{
				$this->id = $id;
		}

		/**
		 *
		 * Set the class
		 *
		 * @param      string className
		 *
		 */
		public function setClassName($className)
		{
				$this->className = $className;
		}

		/**
		 *
		 * Get the class name
		 *
		 * @return     string className
		 *
		 */
		public function getClassName()
		{
				return $this->className;
		}

		private function setPeerName($peerName)
		{
				$this->peerName = $peerName;
		}

		/**
		 *
		 * Get the peer name
		 *
		 * @return     string peerName
		 *
		 */
		public function getPeerName()
		{
				return $this->peerName;
		}

		/**
		 * Build the form
		 *
		 * @return     void
		 *
		 */
		public function build()
		{

				if (!class_exists($this->peerName)) {
						// some autoloading, dunno if it should belong here.
						// or in the users autoload function
						//$dbMap = call_user_func(array($this->peerName, 'getMapBuilder'));
						// TODO: implement this.
				}

				if (empty($this->id)) {
						// create empty instance of this class
						$this->obj = new $this->className();
				} else {
						// find the object.
						if (!$this->obj = call_user_func(array($this->peerName, 'retrieveByPK'), $this->id)) {
								// for help me god..  what to do ?
								throw new PropelException("HTML_QuickForm_Propel::build(): $this->peerName::retrieveByPK($this->id) failed.");
						}

				}

				// note: getTableMap is protected by default.
				// so do this handstand to get the tableMap
				$mapBuilder = call_user_func(array($this->peerName, 'getMapBuilder'));

				// Note: $dbMap is re-used below to determine foreign table
				$dbMap = $mapBuilder->getDatabaseMap();

				// Get the column names for this table.
				$this->cols = $dbMap->getTable(constant("$this->peerName::TABLE_NAME"))->getColumns();

				// Do it the HTML_QuickForm way and use defaultValues
				// instead of setValue() on every element.
				// we have to first loop through the columns
				foreach ($this->cols as $colName=>$col) {


						$elementType = $this->typeMapping[$col->getCreoleType()];

						if ($elementType == 'date') {
								// null returns timestamp
								$value = $this->obj->{'get'.$col->getPhpName()}(null);
						} else {

								$value  = $this->obj->{'get'.$col->getPhpName()}();

						}

						$defaultValues[$colName] = $value;
				}

				$this->setDefaults($defaultValues);

				foreach ($this->cols as $colName=>$col) {

						if ($this->isColumnHidden($colName)) {
								continue;
						}

						if ($col->isPrimaryKey()) {
								// create a hidden field with primary key
								if (!$this->checkColumn($colName, HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE)) {
								        $this->addElement('hidden', $col->getColumnName(), $col->getColumnName());
								        continue;
								}
						}

						// element's title
						$colTitle = $this->getColumnTitle($colName);

						if ($col->isForeignKey()) {

								// TODO: check if user created an optional method for populating the select form
								// this populating of the select box is just some way to show joined items in a form.
								// it could also be checkboxes, radio buttons or whatever kind of widget.

								$relatedTable = $dbMap->getTable($col->getRelatedTableName());
								$relatedCols = $relatedTable->getColumns();
								$relatedPeer = $relatedTable->getPhpName().'Peer';

								if (is_callable($relatedPeer, 'doSelect')) {


								        // TODO: allow set this criteria.
								        $c = new Criteria;

								        $relatedList = call_user_func(array($relatedPeer,'doSelect'), $c);

								        $colConstant        = constant($this->peerName.'::'.$colName);
								        //$relatedColConstant = constant($relatedPeer.'::'.$relatedCol->getColumnName());
								        $relatedGetter      = 'getPrimaryKey';


								        // TODO: this needs to be array based, to support multiple foreign columns
								        if (isset($this->joinMap[$colConstant])) {
								                // translate to getter
								                $relatedColConstant = $this->joinMap[$colConstant];
								                if (!$relatedTable->containsColumn($relatedColConstant)) {
								                        // throw exception, there is no such column
								                        throw new PropelException('HTML_QuickForm_Propel::build(): there is no column named '.$relatedTable->normalizeColName($relatedConstant).'in '.$relatedTable->getTableName().' while trying to build the select list');
								                }
								                $nameColumn = $relatedTable->getColumn($relatedColConstant);
								                $relatedGetter = 'get'.$nameColumn->getPhpName();
								        } else {
								                //auto detection
								                // determine the first string column
								                foreach ($relatedCols as $relatedCol) {
								                        if ($relatedCol->getType() == 'string') {
								                                $relatedGetter = 'get'.$relatedCol->getPhpName();
								                                break;
								                        }
								                }
								        }


								        $selectList = array();

								        // TODO: not hardcoded here.
								        $selectList[null] = _('Please selection an option');

								        foreach ($relatedList as $relObj) {
								                $key = $relObj->getPrimaryKey();

								                if (false OR $yesWannaUseEntireObjectsToUseItInTemplate) {
								                        // TODO: IMPLEMENT THIS.
								                        $selectList[$key] = $relObj;
								                } elseif (false OR $forceSomeKindOfColumnToBeDisplayed) {
								                        // TODO: IMPLEMENT THIS.
								                } else {
								                        $selectList[$key] = $relObj->{$relatedGetter}();
								                }
								        }

								        if (count($selectList) > 1) { // value of 1 depends on select message being set.
								                $select =& $this->addElement('select', $colName, $colTitle, $selectList);
								        } else {
								                // what to do if no records exists in the foreign table ?
								                $this->addElement('static', $colName, $colTitle, _('No Records'));
								        }

								}

								// do some recursion ?

						} else {

								//TODO: the mapping is not so generic anymore (to many exceptions)
								$elementType = $this->typeMapping[$col->getCreoleType()];

								if ($col->getCreoleType() == CreoleTypes::BOOLEAN) {
								        // TODO: describe how to override these options.
					$radio = array();
								        $radio[] = HTML_QuickForm::createElement('radio', null, null, 'Yes', true);
								        $radio[] = HTML_QuickForm::createElement('radio', null, null, 'No', false);
								        $el = $this->addGroup($radio,  $colName, $colName);


								} else {

								        $el = $this->addElement(
								                        $elementType,
								                        $colName,
								                        $colTitle);

								        if ($elementType == 'text') {
								                $el->setMaxLength($col->getSize());
								        }

								        if ($col->getCreoleType() == CreoleTypes::TIMESTAMP) {

								                /* Option Info:
								                   var $_options = array(
								                   'language'         => 'en',
								                   'format'           => 'dMY',
								                   'minYear'          => 2001,
								                   'maxYear'          => 2010,
								                   'addEmptyOption'   => false,
								                   'emptyOptionValue' => '',
								                   'emptyOptionText'  => '&nbsp;',
								                   'optionIncrement'  => array('i' => 1, 's' => 1)
								                   );
								                 */

								                // hmm, don't like it but there seems to be no public method
								                // to set an option afterwards
								                $el->_options['language'] = $this->lang;
								                // TODO: is the format always the same in propel ?
								                $el->_options['format']   = 'Y-F-d H:i:s';

								        }

								}
								// add an html id to the element
								$this->addElementId($el, $colName);

								//$el->setValue($value);

								// required rule for NOT NULL columns
								if ($col->isNotNull()) {
								    // TODO: What error message should we use?
								    $this->addRule($colName,
								        $this->getColumnTitle($colName) . ' is required',
								        'required');
								}

								if ($col->hasValidators()) {

								        foreach ($col->getValidators() as $validatorMap) {

								                $this->addRule($colName,
								                                $validatorMap->getMessage(),
								                                $this->ruleMapping[$validatorMap->getName()],
								                                $validatorMap->getValue(),
								                                $this->defaultRuleType
								                              );

								        }
								}

						}
				}

				// should HTML_QuickForm_Propel add this ?
				$this->addElement('submit', 'submit', 'Submit');

				// do this for the developer, can't think of any case where this is unwanted.
				$this->applyFilter('__ALL__', 'trim');

		}

		/**
		 *
		 * Use it to change the locale used for the Date element
		 *
		 * @param      string locale
		 * @return     void
		 *
		 */
		public function setLang($lang)
		{
				$this->lang = $lang;
		}

		/**
		 *
		 * Save the form.
		 *
		 * @return     void
		 *
		 */
		public function save()
		{
				$this->copyToObj();
				$this->obj->save();
		}

		/**
		 *
		 * Copy form values to Obj.
		 *
		 * @return     void
		 *
		 */
		public function copyToObj()
		{
				// TODO: check what process does, if we leave out anything important.

				if (!isset($this->cols)) {
						// throw some error, form cannot be saved before it is build.
						throw new PropelException('HTML_QuickForm_Propel::save(): form cannot be saved before it is build.');
				}

				foreach ($this->cols as $colName=>$col) {

						// Has the form got this element?
						if ($this->isColumnHidden($colName))
						{
							continue;
						}

						$value = $this->getElementValue($colName);
						if ($value instanceof HTML_QuickForm_Error)
						{
							// TODO: What should we do if an error has occured?
							continue;
						}
						$elementType = $this->typeMapping[$col->getCreoleType()];

						// quickform doesn't seem to give back a timestamp, so calculate the date manually.
						if ($elementType == 'date') {

								$date = array(
								                'D' => null,
								                'l' => null,
								                'd' => null,
								                'M' => null,
								                'm' => null,
								                'F' => null,
								                'Y' => null,
								                'y' => null,
								                'h' => null,
								                'H' => null,
								                'i' => null,
								                's' => null,
								                'a' => null,
								                'A' => null
								             );

								foreach ($value as $key=>$val)  {
								        $date[$key] = $val[0];

								}

								$value = mktime($date['h'], $date['m'], $date['s'], $date['M'], $date['d'], $date['Y']);
						}

						$this->obj->{'set'.$col->getPhpName()}($value);
				}
		}

		/**
		 *
		 * Get the object we are operating on.
		 *
		 * @return     object a propel object
		 *
		 */
		public function getObj()
		{
				return $this->obj;
		}

		/**
		 * What to do if a delete button is added
		 * and the user clicks on it, after the object has been delete in save()
		 */
		public function onDelete()
		{


		}

		public function createDeleteButton()
		{
				return $this->addElement('submit', 'delete', 'Delete');
		}

		public function isColumnHidden($column)
		{
				if ($this->checkColumn($column, HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN) && $this->columnMode == HTML_QUICKFORM_PROPEL_ALL_COLUMNS) {
						return true;
				}

				if (!$this->checkColumn($column, HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE) && $this->columnMode == HTML_QUICKFORM_PROPEL_NO_COLUMNS) {
						return true;
				}

				return false;
		}

		private function checkColumn($column, $state)
		{
				if (isset($this->columnVisibility[$column])) {
						return ($this->columnVisibility[$column] == $state);
				} else {
						return false;
				}
		}

		/**
		 *
		 * Sets the default visibility mode
		 *
		 * This must be either:
		 * HTML_QUICKFORM_PROPEL_NO_COLUMNS or
		 * HTML_QUICKFORM_PROPEL_ALL_COLUMNS
		 *
		 * @param      string $column column name
		 * @return     void
		 *
		 */
		public function setColumnMode($mode)
		{

				if ($mode != HTML_QUICKFORM_PROPEL_NO_COLUMNS && $mode != HTML_QUICKFORM_PROPEL_ALL_COLUMNS) {

						throw new PropelException('HTML_QuickForm_Propel::setColumnMode(): invalid mode passed.');

				}

				$this->columnMode = $mode;
		}

		/**
		 *
		 * Tell HTML_QuickForm_Propel it should hide this column
		 * It is now passed like ID instead of somePeer::ID
		 * The latter is better, but the array_keys of the columns are in ID format and not somePeer::ID
		 *
		 * @param      string $column column name
		 * @return     void
		 *
		 */

		public function hideColumn($column)
		{
				$this->columnVisibility[$column] = HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN;
		}

		/**
		 *
		 * Tell HTML_QuickForm_Propel it should show this column
		 *
		 * It is now passed like ID instead of somePeer::ID
		 * The latter is better, but the array_keys of the columns are in ID format and not somePeer::ID
		 *
		 * @param      string $column column name
		 * @param      string $title Title for the column, not required
		 * @return     void
		 */
		public function showColumn($column, $title = NULL)
		{
				$this->columnVisibility[$column] = HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE;
				if ($title !== NULL)
				{
					$this->setColumnTitle($column, $title);
				}
		}

		/**
		 *
		 * assign a title to the column
		 *
		 * @param      string $column
		 * @param      string $title
		 * @return     void
		 */
		public function setColumnTitle($column, $title)
		{
			$this->columnTitles[$column] = $title;
		}

		/**
		 *
		 * returns column's title
		 *
		 * @param      string $column
		 * @return     void
		 */
		public function getColumnTitle($column)
		{
			// TODO: check if $column exists
			return (array_key_exists($column, $this->columnTitles))
				? $this->columnTitles[$column]
				: $column;
		}

		/**
		 *
		 * Try to automatically join all relatedTables.
		 * NOT IMPLEMENTED
		 *
		 * @param      boolean $bool
		 * @return     void
		 */
		public function autoJoin($bool)
		{
				$this->autoJoin = $bool;
		}

		/**
		 * Override this if you don't like the (strtolower) default
		 *
		 * @param      HTML_QuickForm_Element $el
		 * @param      string $colName
		 * @return     void
		 */
		protected function addElementId($el, $colName)
		{
				$el->updateAttributes(array('id'=>strtolower($colName)));
		}

		/**
		 *
		 * Set the default rule typef
		 * @param      string $type
		 * @return     void
		 *
		 */
		public function setDefaultRuleType($type)
		{
				$this->defaultRuleType = $type;
		}

		/**
		 *
		 * UNFINISHED
		 *
		 * Probably it would be nice to be able to add this to the schema xml
		 *
		 * TODO: further implement multiple columns for the select list
		 *
		 * @var        colName constant
		 * @var        foreignColName mixed (constant/array of columnName constants)
		 * @var        $seperator string Only used if foreignColName is an array
		 */

		public function joinColumn($colName, $foreignColName, $seperator = null)
		{
				if (isset($seperator)) {
						$this->seperator = $seperator;
				}
				$this->joinMap[$colName] = $foreignColName;
		}

}
