<?php
class TeiApi {

	public $tei;
	public $xpath;
	public $fileName;

	public function __construct($tei) {
	    if($tei instanceof TeiDom) {
    	        $this->tei = $tei->dom;
    		$this->xpath = $tei->xpath;
	    } else {
	        throw new Exception('TeiApi must be passed a TeiDom object');
	    }

	    $text = strtolower($tei->projectData['post-title']);
        $fileName = preg_replace('/\s/', "_", $text);
        $fileName = mb_ereg_replace('/[^\w\-]/', '', $fileName);
        $fileName = trim($fileName, "_");

        $fileName = rtrim($fileName, ".");
	    $this->fileName = $fileName;
	}

	public function getFileName() {
        return $this->fileName;
	}

	/* Accessors for building output formats */

	/**
	* nodeToArray gives a 'flattened' array of the node and subnode values.
	* E.g. array('elName'=>'value', 'elName2'=>'value')
	* @param DOMNode
	* @return Array
	*/

	private function nodeToArray($node, $deep = true, $followRefs = false) {

		$retArray = array();

		if( ! $node ) {
			return $retArray;
		}

		if($node->nodeType == XML_ATTRIBUTE_NODE) {
			$retArray = array('attrName'=>$node->nodeName, 'value'=>$node->nodeValue);
			return $retArray;
		}

		$retArray['elName'] = $node->nodeName;

		$attNodes = $this->xpath->query("@*", $node);
		$retArray['atts'] = array();
		foreach($attNodes as $att) {
			$retArray['atts'][$att->nodeName] = $att->nodeValue;
		}


		if($node->nodeName == 'param') {
			$retArray[$node->getAttribute('name')] = $node->textContent;
		}

		if( !empty($node->firstChild) && ( $node->firstChild->nodeType == XML_TEXT_NODE || $node->firstChild->nodeType == XML_CDATA_SECTION_NODE ) ) {
			$retArray['value'] = $node->textContent;
			return $retArray;
		}

		if( ($node->nodeName == 'div') && ( in_array(HTML, $retArray['atts']) )  ) {
			$retArray['value'] = $this->getNodeXML($node);
		}

		if( ! $deep ) {
			return $retArray;
		}

		foreach($node->childNodes as $childNode) {

			if( $childNode->nodeType != XML_ELEMENT_NODE ){
				continue;
			}

			$plName = $childNode->nodeName . "s";
			if( ! isset($retArray[$plName])) {
				$retArray[$plName] = array();
			}
			$retArray[$plName][] = $this->nodeToArray($childNode, $deep);

			if($followRefs && $childNode->hasAttribute('ref')) {
				$ref = $childNode->getAttribute('ref');
				$nd = $this->getNodeDataByParams(array('id'=>$ref));
				$retArray[$plName][] = $nd;
			}

			//if empty, get rid of it
			if ( count($retArray[$plName]) == 0 ) {
				unset($retArray[$plName]);
			}
		}


		return $retArray;
	}



	/**
	 * Retrive data in the node
	 * Returns either the node itself or a flat array containing data in the node and its children.
	 * Allowed params:
	 * array('id'=> , an element id
	 * 		'section'=> ,  'front', 'body', or 'back' of the tei:text
	 * 		'partNumber' => , part number within the section
	 * 		'itemNumber' => , item number within the part
	 * 		'subPath' => , additional path beyond the above parameters
	 * 		'contextNode' => , the DOMNode context of the query
	 * 		'asList'=>, boolean if you want the whole list
	 *
	 *
	 * )
	 *
	 * @param array $params
	 * @param boolean $asNode = false
	 * @return mixed DOMNode or array
	 */

//@TODO: this is an epic mess
	private function getNodeDataByParams($params, $firstOnly = true) {

		extract($params);
		$queryString = $this->buildQueryString($params);

		if(isset($contextNode) ) {
			$nodeList = $this->getNodeListByXPath(array('xpath'=>$queryString, 'contextNode'=>$contextNode) );
		} else {
			$nodeList = $this->getNodeListByXPath($queryString);
		}

		if(! $nodeList ) {
			return false;
		}

		// go through the possibilities of $asNode and $firstOnly
		// if $asNode return in each branch, else make it an array
		// first, the $firstOnly cases
		if($firstOnly) {
			$node = $nodeList->item(0);
			if($asNode) {
				return $node;
			}
			return $this->nodeToArray($node);
		}
        //now the asNode cases
		if($asNode) {
			return $nodeList;
		}
        //not asNode, so build and return the array
		$returnArray = array();
		foreach($nodeList as $node) {
			$returnArray[] = $this->nodeToArray($node);
		}
		return $returnArray;
	}

	private function getNodeTargetData($node) {
		//get id and a label/title
		$id = $node->getAttribute('xml:id');
		$titleNode = $this->getNodeListByXPath(array('xpath'=>"tei:head/tei:title", 'contextNode'=>$node), true);
		$title = $titleNode->firstChild->nodeValue;
		return array('id'=>$id, 'title'=>$title);
	}

	/**
	 * dump the node to a string
	 * @param DOMNode $node a node
	 * @return string
	 */

	private function getNodeXML($node, $atts = false) {
		if($atts) {
			foreach($atts as $att=>$val) {
				$node->setAttribute($att, $val);
			}
		}
		return $this->tei->saveXML($node);
	}


	private function getParentItem($node, $asNode = false) {
		while( $node->getAttribute('type') != 'libraryItem') {
			$node = $node->parentNode;

		}
		if($asNode) {
			return $node;
		}
		return $this->nodeToArray($node, false);
	}

	private function getParentItemId($node) {
		while( $node->getAttribute('type') != 'libraryItem') {
			$node = $node->parentNode;
		}
		return $node->getAttribute('xml:id');
	}

	/**
	 * get the node list for an XPath
	 * @param mixed $xpath as string, an xpath. as array: array('xpath'=>$xpath, 'contextNode'=> DOMNode)
	 * @param $firstOnly = false return only the first match
	 * @return mixed DOMNodeList or DOMNode
	 */

	private function getNodeListByXPath($xpath, $firstOnly = false) {

		if(is_array($xpath)) {
			$nodeList = $this->xpath->query($xpath['xpath'], $xpath['contextNode']);
		} else {
			$nodeList = $this->xpath->query($xpath);
		}

		if($nodeList->length == 0 ) {
			return false;
		}
		if($firstOnly) {
			return $nodeList->item(0);
		}
		return $nodeList;
	}

	/**
	 * get the project title
	 * @param $valueOnly = false whether to return the value only or wrap in a span
	 * @return string
	 */


//TODO: make option to return node like other methods
	public function getProjectTitle($valueOnly = false) {

		$queryString = "//tei:head[@type='titlePage']/tei:bibl/tei:title[@type='main']";
		$titleNode = $this->getNodeListByXPath($queryString, true);
		if($titleNode) {
    		if($valueOnly) {
    			return $titleNode->firstChild->nodeValue;
    		}
    		return $this->getNodeXML($titleNode->firstChild);
		}
        return false;
	}

	/**
	 * get the project subtitle
	 * @param $valueOnly = false whether to return the value only or wrap in a span
	 * @return string
	 */

	public function getProjectSubTitle($valueOnly = false) {

		$queryString = "//tei:head[@type='titlePage']/tei:bibl/tei:title[@type='sub']";
		$subTitleNode = $this->getNodeListByXPath($queryString, true);
		if($subTitleNode) {
    		if($valueOnly) {
    			return $subTitleNode->firstChild->nodeValue;
    		}
    		return $this->getNodeXML($subTitleNode->firstChild);
		}
		return false;
	}

	/**
	 * get info about the project creator, or just the display name
	 * @param $asStructured = false whether to return an array with complete data. requires option includeCreatorData = true when construction TeiDOM
	 * @return mixed array of data or string
	 */

	public function getProjectCreator($asStructured = false, $asNode = false) {
		$queryString = "//tei:author[@role = 'projectCreator']";
		$creator = $this->getNodeListByXPath($queryString, true);
        if($creator) {
    		if($asStructured) {
    			$ref = $creator->getAttribute('ref');
    			$structuredCreator = $this->tei->getElementById($ref);
    			if($asNode) {
    			    return $structuredCreator;
    			}
    			return $this->nodeToArray($structuredCreator);
    		}
    		if($asNode) {
    			return $creator->firstChild;
    		}
    		return $creator->firstChild->textContent;
        }

        return false;
	}

	public function getProjectAssertedAuthors($asNode = false) {
	    $xpath = "//tei:author[@role = 'assertedAuthor']";
	    $assertedAuthors = $this->getNodeListByXPath($xpath, true);
	    if($assertedAuthors) {
	        if($asNode) {
	            return $assertedAuthors->firstChild;
	        }
	        return $assertedAuthors->firstChild->textContent;
	    }
	    return false;
	}

	/**
	 * get copyright/license information about the project
	 * @param $asStructured = false return as structured data or human-readable
	 * return string
	 */
//TODO: make it return a node,
	public function getProjectCopyright($asStructured = false, $html = true) {

		if($asStructured) {

			$cr = $this->getNodeListByXPath("//tei:publicationStmt/tei:availability[@rend='structured']/tei:ab", true);

			if($cr->parentNode->getAttribute('status') == 'c') {
				return "<span>Copyright</span>";
			}

		} else {
			$cr = $this->getNodeListByXPath("//tei:publicationStmt/tei:availability[@rend='literal']/span", true);

			if($cr->parentNode->getAttribute('status') == 'c') {
				return "<span>Copyright</span>";
			}
		}
		if($html) {
			return $this->getNodeXML($cr);
		}

		return $cr->firstChild->textContent;

	}

	/**
	 * get edition information about the project
	 * @param $asStructured = false return as structured data or human-readable
	 * return string
	 */

	public function getProjectEdition($asStructured = false) {
		$edition = $this->getNodeListByXPath("//tei:editionStmt/tei:ab[@rend='literal']/span", true);
		return $this->getNodeXML($edition);
	}

	/**
	 * get an output param set on the export screen
	 * @param $param = false a single param value to return
	 * @param $asNode = false whether to return as a node or a string
	 * @return mixed DOMNode or string or array
	 */

	public function getProjectOutputParams($param = false, $asNode = false) {
		$xpath = "//anth:outputDecl/anth:outputParams";
		if($param) {
			$xpath .= "/anth:param[@name='$param']";
		}
		$params = array('subPath'=>$xpath,
						'asNode'=>$asNode
						);
		$data = $this->getNodeDataByParams($params);
		if($param) {
			return $data[$param];
		}

		return $data;
	}

	/**
	 * return the publication date
	 * @return string
	 */

	public function getProjectPublicationDate() {
		$query = "//tei:front/tei:head/tei:bibl/tei:data[@type = 'created']";
		$params = array('section'=>'front',
						'subPath'=>"/tei:head/tei:bibl/tei:date[@type = 'created']",
						'asNode'=>false
					);
		$data = $this->getNodeDataByParams($params);
		return $data['value'];
	}

	/**
	 * get the number of parts in a section
	 * @param $section = 'body' the section, front, body, or back
	 * @return int
	 */

	public function getSectionPartCount($section = 'body') {
		$count = $this->xpath->evaluate("count(//tei:$section/tei:div[@type='part'])");
		return $count;
	}

	/**
	 * get the id set for a part within a section
	 * @param $section the section. front, body, or back
	 * @param $partNumber the number of the part within the section
	 * @return string
	 */

	public function getSectionPartId($section, $partNumber) {
		$params = array('section'=> $section,
						'partNumber' => $partNumber,
						'subPath' => "@xml:id",
						'asNode'=>false
						);
		$data = $this->getNodeDataByParams($params);
		return $data['value'];
	}



	public function getSectionPartHead($section, $partNumber, $asNode = false) {
		$params = array('section' => $section,
		'partNumber'=>$partNumber,
		'subPath'=>'/tei:head',
		'asNode'=>$asNode);
		return $this->getNodeDataByParams($params);
	}

	/**
	 * get the title for a part within a section
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $asNode whether to return the DOMNode
	 * @return mixed string or DOMNode
	 */

	public function getSectionPartTitle($section, $partNumber, $asNode = false) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'subPath'=>'/tei:head/tei:title',
		'asNode'=>true);

		$data = $this->getNodeDataByParams($params);
        if($data) {
            if($asNode) {
			    return $data;
		    }
		    return $this->getNodeXML($data->firstChild);
        }
        return false;
	}




	/**
	 * get the number of items in a part in a section
	 * @param $section = 'body' the section, front, body, or back
	 * @param $partNumber the number of the part within the section
	 * @return int
	 */

	public function getSectionPartItemCount($section, $partNumber = null) {
		switch($section) {
			case 'front':
				$count = $this->xpath->evaluate("count(//tei:$section/tei:div)");
			break;

			case 'body':
				$count = $this->xpath->evaluate("count(//tei:$section/tei:div[@type='part'][@n='$partNumber']/tei:div[@type='libraryItem'])");
			break;

			case 'back':
				$count = $this->xpath->evaluate("count(//tei:$section/tei:div)");
			break;

		}


		return $count;
	}

	public function getSectionPartItemHead($section, $partNumber, $itemNumber, $asNode = false) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'itemNumber'=>$itemNumber,
		'asNode'=>$asNode);
		return $this->getNodeDataByParams($params);
	}

	/**
	 * get the title for an item within a part within a section
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $asNode whether to return the DOMNode
	 * @return mixed string or DOMNode
	 */


	public function getSectionPartItemTitle($section, $partNumber, $itemNumber, $asNode = false) {
		$params = array('section'=> $section,
    		'partNumber'=>$partNumber,
    		'itemNumber'=>$itemNumber,
    		'subPath'=>"/tei:head/tei:title",
    		'asNode'=>true);
		$data = $this->getNodeDataByParams($params);
		if($data) {
			if($asNode) {
    			return $data;
    		}
		    return $this->getNodeXML($data->firstChild);
		}
		return false;
	}

	/**
	 * get the id set for an item within a part within a section
	 * @param $section the section. front, body, or back
	 * @param $partNumber the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @return string
	 */

	public function getSectionPartItemId($section, $partNumber, $itemNumber) {
		$params = array('section'=> $section,
						'partNumber' => $partNumber,
						'itemNumber' => $itemNumber,
						'subPath' => "/@xml:id",
						'asNode'=>false
						);
		$data = $this->getNodeDataByParams($params);
		return $data['value'];
	}

	/**
	 * get info about the original author of the content anthologized. (that is the author of the post or page, not necessarily the creator of the item within the project)
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $valueOnly = true give just the display name
	 * @param $asNode whether to return the DOMNode
	 * @return mixed string or array
	 */

	public function getSectionPartItemOriginalAuthor($section, $partNumber, $itemNumber, $valueOnly = true, $asNode = false) {
		$params = array('section'=> $section,
						'partNumber' => $partNumber,
						'itemNumber' => $itemNumber,
						'subPath' => "/tei:head/tei:bibl/tei:author[@role='originalAuthor']",
						'asNode'=>$asNode
						);

		$data = $this->getNodeDataByParams($params);

		if($valueOnly) {
			return $data['spans'][0]['value'];
		}
		return $data;

	}

	/**
	 * get info about anthologizer of the content. that is, who added it to the project
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $asNode whether to return the DOMNode
	 * @param $valueOnly = true give just the display name
	 * @return mixed string or array
	 */

	public function getSectionPartItemAnthologizer($section, $partNumber, $itemNumber, $asNode = false, $valueOnly = true) {
		$params = array('section'=> $section,
						'partNumber' => $partNumber,
						'itemNumber' => $itemNumber,
						'subPath' => "/tei:head/tei:bibl/tei:author[@role='anthologizer']",
						'asNode'=>$asNode
						);

		$data = $this->getNodeDataByParams($params);
		if($valueOnly) {
			return $data['spans'][0]['value'];
		}
		return $data;

	}
	/**
	 * get info about the author, as set in the Anthologize project administration pages
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $asNode whether to return the DOMNode
	 * @param $valueOnly = true give just the display name
	 * @return mixed string or array
	 */
	public function getSectionPartItemAssertedAuthor($section, $partNumber, $itemNumber, $asNode = false, $valueOnly = true) {
		$params = array('section'=> $section,
						'partNumber' => $partNumber,
						'itemNumber' => $itemNumber,
						'subPath' => "/tei:head/tei:bibl/tei:author[@role='assertedAuthor']",
						'asNode'=>$asNode
						);

		$data = $this->getNodeDataByParams($params);
		if($asNode) {
		    if($valueOnly) {
		        return $data->textContent;
		    }
		    return $data;
		}
		if($valueOnly) {
			return $data['spans'][0]['value'];
		}
		return $data;

	}

	/**
	 * get the tags and categories for the item
	 * Opinionated comment: the distinction is usually irrelevant across more than one user and blog, so -Subjects covers both, -Tags and -Categories make the distinction
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $asNode whether to return the DOMNode
	 * @return mixed array or DOMNode
	 */

	public function getSectionPartItemSubjects($section, $partNumber, $itemNumber, $asNode = false ) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'itemNumber'=>$itemNumber,
		'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs",
		'asNode'=> $asNode);
		$data = $this->getNodeDataByParams($params, false);
		return $data;
	}

	public function getSectionPartItemTags($section, $partNumber, $itemNumber, $asNode = false ) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'itemNumber'=>$itemNumber,
		'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs[@type='tag']",
		'asNode'=> $asNode);
		$data = $this->getNodeDataByParams($params, false);
		return $data;
	}

	public function getSectionPartItemCategories($section, $partNumber, $itemNumber, $asNode = false ) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'itemNumber'=>$itemNumber,
		'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs[@type='category']",
		'asNode'=> $asNode);
		$data = $this->getNodeDataByParams($params, false);
		return $data;
	}

	/**
	 * get the content for an item within a part within a section
	 * @param $section the section. front, body, or back
	 * @param $partNumer the number of the part within the section
	 * @param $itemNumber the number of the item within the part
	 * @param $asNode whether to return the DOMNode
	 * @return mixed string or DOMNode
	 */


	public function getSectionPartItemContent($section, $partNumber, $itemNumber, $asNode = false) {
		$params = array('section'=> $section,
		'partNumber'=>$partNumber,
		'itemNumber'=>$itemNumber,
		'subPath'=>'/div',
		'asNode'=> true);
		$data = $this->getNodeDataByParams($params);

		if($data) {
    		if ($data->childNodes->length == 0) {
    			return false;
    		}
    		if($asNode) {
    			return $data;
    		}
    		return $this->getNodeXML($data);
		}
        return false;
	}


	public function getIndex($indexName, $asNode = false) {
		$params = array('index'=>$indexName,
						'asNode'=>$asNode,
						);

		return $this->getNodeDataByParams($params);
	}

	public function getIndexItemCount($index) {

		if( is_array($index)) {
			return count($index['lists'][0]['items']);
		} else if ( is_a($index, 'DOMElement') ) {
			$xpath = "list/item";
			return $this->xpath->evaluate("count($xpath)", $index);
		} else {
			throw new Exception('index must be node or array');
		}

	}

	public function getIndexItem($index, $itemNumber) {
		if (is_array($index)) {
			return $index['lists'][0]['items'][$itemNumber];
		} else if (is_a($index, 'DOMElement')) {
			$params = array('contextNode'=>$index,
							'asNode'=>true,
							'subPath'=>"list/item[@n='$itemNumber']"
							);
			return $this->getNodeDataByParams($params);

		} else {
			throw new Exception('index must be node or array');
		}
	}

	public function getIndexItemLabel($item, $asNode = false) {
 		if (is_array($item)) {
			return $item['rs'][0]['spans'][0]['value'];
		} else if (is_a($item, 'DOMElement')) {
			$params = array('contextNode'=>$item,
							'asNode'=>true,
							'subPath'=>"rs"
							);

			$data =  $this->getNodeDataByParams($params);

			if($asNode) {
				return $data;
			}
			return $this->getNodeXML($data);

		} else {
			throw new Exception('item must be node or array');
		}
	}


	public function getIndexItemRef($item, $asNode = false) {
 		if (is_array($item)) {
			$ref = $item['rs'][0]['atts']['ref'];
		} else if (is_a($item, 'DOMElement')) {
			$ref = $item->firstChild->getAttribute('ref');
		} else {
			throw new Exception('index must be node or array');
		}
		return $this->getDetailsByRef($ref);
	}


	public function getIndexItemTargetCount($item) {
		if( is_array($item)) {
			return count($item['listRefs'][0]['rs']);
		} else if ( is_a($item, 'DOMElement') ) {
			$xpath = "listRef/rs"; //looks like when giving a context node, evaluate doesn't want prefixes
			return $this->xpath->evaluate("count($xpath)", $item);
		} else {
			throw new Exception('index must be node or array');
		}
	}

	public function getIndexItemTarget($item, $targetNumber) {
 		if (is_array($item)) {
			return $item['listRefs'][0]['rs'][$targetNumber];
		} else if (is_a($item, 'DOMElement')) {
			$params = array('contextNode'=>$item,
							'asNode'=>true,
							'subPath'=>"listRef/rs[@n='$targetNumber']"
							);

			return $this->getNodeDataByParams($params);
		} else {
			throw new Exception('item must be node or array');
		}
	}

	/**
	 * dig up a detail about the target
	 *
	 * @param DOMElement $target
	 * @param string $detail this is the info you are looking for: ref, role, label
	 */

	public function getIndexItemTargetDetail($target, $detail, $asNode = false) {
 		if (is_array($target)) {

			switch ($detail) {
				case 'ref':
					return $target['atts']['ref'];
				break;

				case 'role':
					return $target['atts']['role'];
				break;

				case 'label':
					return $target['spans'][0]['value'];
				break;

			}
		} else if (is_a($target, 'DOMElement')) {
			switch ($detail) {
				case 'ref':
					return $target->getAttribute('ref');
				break;

				case 'role':
					return $target->getAttribute('role');
				break;

				case 'label':
					if($asNode) {
						return $target->firstChild;
					}
					return $this->getNodeXML($target->firstChild);

				break;
			}
		} else {
			throw new Exception('index must be node or array');
		}
	}


	/**
	 * get the structured data about a person or subject based on their id/username
	 * @param $ref the id/username of the person. (it's a ref attribute in the TEI)
	 * @param $asNode whether to return the DOMNode
	 * @return array
	 */

	public function getDetailsByRef($ref, $asNode = false) {
		$params = array('id'=>$ref ,
						'asNode'=>$asNode);
		return $this->getNodeDataByParams($params);
	}


	/**
	 * dig up a particular piece of data out of the structured array for a user. Basically a helper to sort through the array
	 * @param array $personArray the structured array representing the person
	 * @param string $element the name of the data you want
	 * @return string
	 */

	public function getPersonDetail($personArray, $element) {
		switch ($element) {
			case 'name':
				return $personArray['persNames'][0]['names'][0]['spans'][0]['value'];
			break;

			case 'firstname':
				return $personArray['persNames'][0]['firstnames'][0]['spans'][0]['value'];
			break;

			case 'surname':
				return $personArray['persNames'][0]['surnames'][0]['spans'][0]['value'];
			break;

			case 'bio':
				return $personArray['notes'][0]['divs'][0]['value'];
			break;

			case 'email':
				return $personArray['persNames'][0]['emails'][0]['spans'][0]['value'];
			break;

			case 'count':
				return $personArray['persNames'][0]['nums'][0]['value'];
			break;

			case 'gravatarUrl':
				return isset( $personArray['figures'][0]['graphics'][0]['imgs'][0]['atts']['src'] ) ? $personArray['figures'][0]['graphics'][0]['imgs'][0]['atts']['src'] : '';
			break;

		}
	}

	public function buildQueryString($params) {
		//id, section, and index all start a new queryString
		$queryString = '';
		if(isset($params['id'])) {
		    $this->_filterQueryStringById($queryString, $params['id']);
		}

        if(isset($params['section'])) {
		    $this->_filterQueryStringBySection($queryString, $params['section']);
        }

	    if(isset($params['index'])) {
		    $this->_filterQueryStringByIndex($queryString, $params['index']);
        }


		//these three add onto the queryString, in order
		//only the body should filter by part numbers
	    if(isset($params['partNumber']) && isset($params['section']) && $params['section'] == 'body') {
		    $this->_filterQueryStringByPartNumber($queryString, $params['partNumber']);
        }

		if(isset($params['itemNumber'])) {
		    $this->_filterQueryStringByItemNumber($queryString, $params['itemNumber']);
        }

		if(isset($params['subPath'])) {
		    $this->_filterQueryStringBySubPath($queryString, $params['subPath']);
        }
        return $queryString;
	}

    private function _filterQueryStringById(&$queryString, $id) {
        if(!empty($id)) {
            $queryString = "//*[@xml:id = '$id']";
        }

    }

    private function _filterQueryStringByIndex(&$queryString, $index) {
        if(!empty($index)) {
            $queryString = "//tei:div[@type='index'][@subtype='$index']";
        }

    }

    private function _filterQueryStringBySection(&$queryString, $section) {
        if(!empty($section)) {
            $queryString = "//tei:$section";
        }

    }

    //@TODO: it'd be sweet of me to throw a warning for non-integer
    private function _filterQueryStringByItemNumber(&$queryString, $itemNumber) {
        $queryString .= "/tei:div[@n='$itemNumber']";
    }


    private function _filterQueryStringByPartNumber(&$queryString, $partNumber) {
        $queryString .= "/tei:div[@n='$partNumber']";
    }

    private function _filterQueryStringBySubPath(&$queryString, $subPath) {
        if(!empty($subPath)) {
            $queryString .= "$subPath";
        }

    }



}
