<?php

/**
 * instructions
 * this model provides a structure for the form.
 * here you can modify all the parameter for the content of the form:
 * mainly fields and their types
 * and also some othr parameter such as which string is shown
 * in a selection list as default
 * 
 * how to define fields:
 * you have to add each field to the 
 * field definitions section , 
 * field declarationss section and
 * the rules() function
 * (see below at the corresponding section for further infos)
 * 
 * you also have to define what queries are generated from the user
 * input of each field. do this in the QueryFactory. 
 * make sure you use the same name in all 4 places!
 * and is the same name as in the correspondint solr index field!
 * 
 * you also can add a label for the field in the attributeLabels() function
 * by default the label is generatet automatically 
 * by changing camelcase to single words
 * and start each word upper case
 * e.g. familyName will get the label: Family Name
 * 
 * you also can define more form parameters in the other settings section
 * (see below)
 * 
 * this form is used by the SearchController 
 * that runs the search view (views.search.search.php) customized for this model.
 * 
 * @author s.buers
 *
 */
class GGBNSearchForm extends CFormModel {
	// TODO layout
	// test fields:
	
	// ------------- field definitions -----------------------------
	// here you define all parameters/fields for the form
	// in an array of key=>value:
	// key: name of the field
	// value is an array of parameters to define the field:
	// type: is required! and must be one of the following:
	// text: usual text field
	// checkbox: shows checkbox returns value
	// select: creates a selection list (drop down)
	// if a the parameter 'valueList' is set (to an array of strings)
	// it will be shown.
	// if it is not set, the list will be generated from the index
	// therefore the field name must match an index field
	// (if not an error will appear)
	// suggest: a field that provides suggestion on the input the user makes
	// number: creates a number field, where the user can choose integers.
	// it is recommended to define 'min' and 'max' in the 'config' array
	// deactivated: the field will not be writable
	// hideable: set to 'true' if the field can be added by the user on demand
	// config: is an array of attributes for the <input> elements
	// e.g. 'size' or 'maxlength'
	// e.g. 'familyName' =>array('type'=>'text', 'config'=>array(size'=>45,'maxlength'=>45))
	// (this will end up in a field like this:
	// <input size="45" maxlength="45" name="GGBNSearchForm[familyName]" id="GGBNSearchForm_familyName" type="text" />)
	// alt: if you have a group of fields, that have to be chosen one of them exclusively.
	// create a field in the field declaration section for each but only one in the
	// field definition section with the default selection and put the names of the
	// others in the 'alt' parameter see: familyName
	// TODO do we need or want this static???
	private $_parameters = array (
			'fullScientificName' => array (
					'type' => 'suggest' 
			),
			'familyName' => array (
					// 'alt' => array('orderName', 'className', 'phylumName', 'kingdomName'),
					'type' => 'suggest' 
			)
			// 'hideable'=>'true'
			,
			// 'taxonomyId' => array (
			// 'type' => 'deactivated' ,
			// 'hideable'=>'true'
			// ),
			'country' => array (
					'type' => 'select' 
			)
			// 'valueList' => array('Foo','Bar','Batz')
			,
			// 'continent' => array (
			// 'type' => 'select'
			// // 'type' => 'deactivated'
			// ),
			'sea' => array (
					'type' => 'select',
					'hideable' => 'true' 
			),
			'ocean' => array (
					'type' => 'select',
					// 'type' => 'deactivated',
					'hideable' => 'true' 
			),
			'longitudeFrom' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			'longitudeTo' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			'latitudeFrom' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			'latitudeTo' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			'collectionYearFrom' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			'collectionYearTo' => array (
					'type' => 'text',
					'hideable' => 'true',
					'config' => array ()
					// 'size' => 10
					 
			),
			// 'locality' => array (
			// 'type' => 'text',
			// 'hideable'=>'true'
			// ),
			// 'collectors' => array (
			// 'type' => 'text',
			// 'hideable'=>'true'
			// ),
			// 'collectorNo' => array (
			// // 'type' => 'text',
			// 'type' => 'deactivated',
			// 'hideable'=>'true'
			// ),
			// 'hasTypestatus' => array (
			// 'type' => 'checkbox',
			// // 'type' => 'deactivated',
			// 'hideable'=>'true'
			// ),
			'hasImage' => array (
					'type' => 'checkbox',
					'hideable' => 'true' 
			),
			// 'unitID' => array (
			// //'type' => 'deactivated'
			// 'type' => 'text'
			// ),
			// 'extractionNo' => array (
			// //'type' => 'text'
			// 'type' => 'deactivated'
			// ),
			'institution' => array (
					'type' => 'select',
					'hideable' => 'true' 
			),
			// 'genBankAccessionNo' => array (
			// 'type' => 'deactivated'
			// //'type' => 'text'
			// ),
			// 'genBankRecordAvailable' => array (
			// 'type' => 'deactivated',
			// // 'type' => 'checkbox',
			// 'hideable'=>'true'
			// ),
			// 'boldRecordAvailable' => array (
			// 'type' => 'deactivated'
			// // 'type' => 'checkbox'
			// ),
			'kindofunit' => array (
					'type' => 'select',
					'hideable' => 'true' 
			) 
	)
	// 'boldId' => array (
	// 'type' => 'deactivated',
	// // 'type' => 'text',
	// 'hideable'=>'true'
	// )
	;
	
	/*
	 * ----------------- field declarations ------------------------
	 * put here all the same fields as you defined in the parameters array
	 */
	// voucher/specimen
	
	// fields marked with ***main field*** should be permanent, the other are hidden, and
	// can be added by the user - this is set up with the hideable parameter in the defenition area
	public $familyName; // TODO also other ranks: order, class, phylum, kingdom ***main field***
	public $orderName; // TODO
	public $className; // TODO
	public $phylumName; // TODO
	public $kingdomName; // TODO
	public $fullScientificName; // Species //TODO have also search with * like "ac*" ***main field***
	public $taxonomyId; // TODO later, not yet in index
	public $country; // ***main field***
	public $continent; // TODO
	public $sea; // TODO
	public $ocean; // TODO
	public $longitudeFrom;
	public $longitudeTo;
	public $latitudeFrom;
	public $latitudeTo;
	public $collectionYearFrom;
	public $collectionYearTo;
	public $locality;
	public $collectors;
	public $collectorNo; // TODO search collectornumber and fieldnumber
	public $hasTypestatus; // TODO recheck with Gabi what cases we exactly want to find if this field is choosen (see email to Gabi)
	public $hasImage; // boolean
	public $unitID; // TODO make over when index DB is corrected by Patricia
	                // ***main field*** !!!use multivalued!!!
	                
	// DNA
	                // public $extractionNo;
	public $institution;
	
	// TODO felder "GenBank/EMBL/DDBJ Accession No" und "BOLD Process ID"
	// solange es noch keine spalte sequenceaccession.BoldID gibt,
	// für beide in sequenceaccession.accessionIdentifier suchen
	public $genBankAccessionNo; // TODO
	public $boldId; // TODO
	                
	// TODO beide felder zusammen, solange es noch kein feld sequenceaccession.BoldID gibt,
	                // checke if sequenceaccession.accessionIdentifier ist vorhanden
	public $genBankRecordAvailable; // TODO
	public $boldRecordAvailable; // TODO gibt es eine sequenceaccession.BoldID
	                             // -> erst wenn die spalte in die index db gebaut wurde
	public $kindofunit; // Tissue TODO evtl. weglassen
	
	/*
	 * ----------------- other settings ----------------------------
	 */
	// title of the form:
	// TODO put some html-classes arround the strings
	private $_extendedSearchFormTitle = '<h1>Extended Search</h1>';
	
	// search button text:
	private $_extendedSearchButtonLabel = 'Search';
	
	// what string represents if nothing is chosen in the drop down lists
	// (technically it leads to everything (*))
	private $_selectionListNonChosen = "---";
	
	// string that is presented in a suggestion list if
	// the input does not match to any item
	private $_sugesstionListNoMatch = "-- no match --";
	
	// default size of fields
	// - if you don't give a size in the definition area this value will be used
	private $_fieldSize = 50;
	
	// ---- keep your hands off these parameters---------------
	// ------they will be initialized automatically (e.g see init())
	private $_hideableList = array ();
	
	// ------------- getters--------------------------------------
	public function getParameters() {
		return $this->_parameters;
	}
	public function getExtendedSearchFormTitle() {
		return $this->_extendedSearchFormTitle;
	}
	public function getExtendedSearchButtonLabel() {
		return $this->_extendedSearchButtonLabel;
	}
	public function getFieldsPerRow() {
		return $this->_fieldsPerRow;
	}
	public function getSelectionListNonChosen() {
		return $this->_selectionListNonChosen;
	}
	public function getSugesstionListNoMatch() {
		return $this->_sugesstionListNoMatch;
	}
	public function getHideableList() {
		return $this->_hideableList;
	}
	public function getFieldSize() {
		return $this->_fieldSize;
	}
	
	// @override
	public function init() {
		foreach ( $this->_parameters as $key => $attr ) {
			if (isset ( $attr ['hideable'] ) && $attr ['hideable'] == 'true') {
				$this->_hideableList [] = $key;
			}
		}
	}
	
	// ----------------- validation rules ------------------------
	// @override
	/**
	 * Declares the validation rules.
	 * each field that has no rules has to be at least assigned to the 'safe' validator
	 */
	public function rules() {
		$date = getdate ( time () );
		$year = $date ['year'];
		return array (
				array (
						'latitudeFrom, latitudeTo',
						'numerical',
						'min' => - 90,
						'max' => 90,
						'tooSmall' => 'Coordinate Latitude must not be smaller than {min}.',
						'tooBig' => 'Coordinate Latitude must not be bigger than {max}.' 
				),
				array (
						'longitudeFrom, longitudeTo',
						'numerical',
						'min' => - 180,
						'max' => 180,
						'tooSmall' => 'Coordinate Longitude must not be smaller than {min}.',
						'tooBig' => 'Coordinate Longitude must not be bigger than {max}.' 
				),
				array (
						'collectionYearFrom, collectionYearTo',
						'numerical',
						'min' => 1000,
						'max' => $year,
						'tooSmall' => 'please put Collection Year in four digit representation e.g. "1785" or "2013"',
						'tooBig' => 'Collection Year is in the future.' 
				),
				// make everything else that has no rules valid
				array (
						'familyName, orderName ,className, phylumName, kingdomName, fullScientificName, taxonomyId, country, continent, sea, ocean, collectionYearFrom, collectionYearTo, locality, collectors, collectorNo, hasTypestatus, hasImage, unitID, institution, genBankAccessionNo, genBankRecordAvailable, boldRecordAvailable, kindofunit, boldId',
						'safe' 
				) 
		);
	}
	
	// @override
	/**
	 * Declares customized attribute labels.
	 * If not declared here, an attribute would have a label that is
	 * the same as its name with the first letter in upper case.
	 */
	public function attributeLabels() {
		return array (
				'taxonomyId' => 'Taxonomy ID (NCBI)',
				'fullScientificName' => 'Species',
				'hasImage' => 'Image available',
				'kindofunit' => 'Tissue',
				'hasTypestatus' => 'Type Specimen/Strain',
				'unitID' => 'Sample, Voucher or Strain No',
				'phylumName' => 'Phylum/Division Name' 
		)
		// 'collectorNo'=> "Collector\'s No"
		// TODO: only the ones that should have
		// different labeld from the parameter names of the index
		;
	}
	
	/*
	 * validator for coordinates
	 */
	public function isLongitude($attribute) {
		if (! ((is_double ( $attribute )) && ($attribute <= - 180) && $attribute >= 180)) {
			$this->addError ( $attribute, "this is not a valid coodinate" );
		}
	}
}