public static function loadImageAttributeListByImageDataId(PDO $dbConnection, $imageDataId)
 {
     $preparedStatement = $dbConnection->prepare('SELECT * FROM image_attribute WHERE image_data_id = :imageDataId');
     $preparedStatement->bindParam(':imageDataId', $imageDataId);
     $preparedStatement->execute();
     $outputList = array();
     $resultRow = NULL;
     while ($resultRow = $preparedStatement->fetch(PDO::FETCH_ASSOC)) {
         $imageAttribute = new ImageAttribute($resultRow['id']);
         $imageAttribute->setImageDataId($imageDataId);
         $imageAttribute->setAttribute($resultRow['attribute']);
         $outputList[] = $imageAttribute;
     }
     $preparedStatement = NULL;
     return $outputList;
 }
    public function processRequest(User $user = NULL)
    {
        // if no journey exists, then redirect to the start journey page
        $startJourneyUrl = UrlFormatter::formatRoutingItemUrl('views/StartJourneyView');
        if (!isset($_SESSION['JOURNEY_IMAGE_LIST']) || empty($_SESSION['JOURNEY_IMAGE_LIST'])) {
            header("Location: {$startJourneyUrl}");
            exit;
        }
        parent::displayHeader($user, 'Finish Journey');
        //print( "JOURNEY IMAGE LIST: " ); print_r( $_SESSION['JOURNEY_IMAGE_LIST'] ); print( "<br/>" );
        // load the image data for images encountered on the journey
        $dbConnection = DbConnectionUtil::getDbConnection();
        $imageDataList = NULL;
        if (!empty($_SESSION['JOURNEY_IMAGE_LIST'])) {
            $imageDataList = ImageData::loadImageDataListByIdSet($dbConnection, $_SESSION['JOURNEY_IMAGE_LIST']);
        }
        //print( "JOURNEY ATTRIBUTE MAP: " ); print_r( $_SESSION['JOURNEY_ATTRIBUTE_MAP'] ); print( "<br/>" );
        // if possible, load image data for images with common attributes
        $commonImageDataList = NULL;
        $commonAttribute = NULL;
        //print( "<br/>att map: " ); print_r( $_SESSION['JOURNEY_ATTRIBUTE_MAP'] ); print("<br/>" );
        if (isset($_SESSION['JOURNEY_ATTRIBUTE_MAP']) && !empty($_SESSION['JOURNEY_ATTRIBUTE_MAP'])) {
            // find the attribute with the maximum number of entries
            $maxAttribute = NULL;
            $maxAttributeCount = 0;
            foreach ($_SESSION['JOURNEY_ATTRIBUTE_MAP'] as $attribute => $count) {
                if ($maxAttribute == NULL || $maxAttributeCount < $count) {
                    $maxAttribute = $attribute;
                    $maxAttributeCount = $count;
                }
            }
            $commonAttribute = $maxAttribute;
            // find images with common attributes
            $tempCommonImageIdList = ImageAttribute::loadCommonAttributeImageIdList($dbConnection, $commonAttribute, $_SESSION['JOURNEY_IMAGE_LIST']);
            $commonImageIdList = array();
            foreach ($tempCommonImageIdList as $imageId) {
                if (!in_array($imageId, $_SESSION['JOURNEY_IMAGE_LIST'])) {
                    $commonImageIdList[] = $imageId;
                }
            }
            if (!empty($commonImageIdList)) {
                $commonImageDataList = ImageData::loadImageDataListByIdSet($dbConnection, $commonImageIdList);
            }
        }
        // display the journey in an image grid
        ?>
	<p class="imageGridHeader">Your Journey Through Art</p>
	<div class="centerWrapper">
        <div class="imageGrid">
	<?php 
        foreach ($imageDataList as $imageData) {
            $this->displayImageDetailLink($imageData);
        }
        ?>
	</div>
	</div>
	<?php 
        if ($commonImageDataList != NULL) {
            ?>
	    <p class="imageGridHeader">Suggested Art</p>
	    <div class="centerWrapper">
		<p>Based upon your choices here is a selection of other art pieces to examine</p>
	    <div class="imageGrid">
	    <?php 
            foreach ($commonImageDataList as $imageData) {
                $this->displayImageDetailLink($imageData);
            }
            ?>
	    </div>
	    </div>
	    <?php 
        }
        $saveJourneyUrl = UrlFormatter::formatRoutingItemUrl('actions/SaveJourneyAction');
        ?>
	<script type="text/javascript">
	function validate( ) {
	    var result = true;
	    $("#errorSection").html("");
	    var nameVal = $("#journey_name_field").val( );
	    if( nameVal == null || nameVal == "" ) {
		$("#errorSection").append( "<span clas=\"errorMessage\">Journey Name Required</span><br/>" );
		$("#errorSection").css( "display", "inline-block");
		$("#journey_name_field_label").css( "color", "#EE3124" );
		result = false;
	    }
	    var commentsVal = $("#journey_comments_field").val( );
	    if( commentsVal == null || commentsVal == "" ) {
		$("#errorSection").append( "<span clas=\"errorMessage\">Comments Required</span><br/>" );
		$("#errorSection").css( "display", "inline-block");
		$("#journey_comments_field_label").css( "color", "#EE3124" );
		result = false;
	    }
	    return result;
	}
	</script>
	<p class="imageGridHeader">Journey Feedback</p>
        <p style="width:50%">
	     You are now encouraged to take a moment to reflect on your journey through art. Consider the feelings which were illicited during the experience. Also think about how each piece might have had an affect on your perception of subsequent pieces. Please share your thoughts in the comments field.
	</p>
	<form class="imageForm" method="POST" action="<?php 
        echo $saveJourneyUrl;
        ?>
" onsubmit="return validate( )">
	     <div class="errorSection" id="errorSection"></div>
	     <br/>
	     <label id="journey_name_field_label" for="journey_name_field">Journey Name</label>
	     <br/>
             <input id="journey_name_field" type="text" name="<?php 
        echo SaveJourneyAction::POST_PARAM_JOURNEY_NAME;
        ?>
"/>
             <br/>
             <label id="journey_comments_field_label" for="journey_comments_field">Comments</label>
             <br/>
             <textarea id="journey_comments_field" rows="10" cols="100" name="<?php 
        echo SaveJourneyAction::POST_PARAM_JOURNEY_COMMENTS;
        ?>
" value=""></textarea>
             <br/>
             <input class="button" type="submit" value="Save"/>
	</form>
	<?php 
        parent::displayFooter();
    }
    public function processRequest(User $user = NULL)
    {
        // attempt to parse and load the next image id
        $nextImageId = RequestParser::parseRequestParam($_REQUEST, self::GET_PARAM_NEXT_IMAGE_ID, RequestParser::PARAM_FILTER_TYPE_INT);
        // if no image was specified, redirect to the start journey view
        $startJourneyUrl = UrlFormatter::formatRoutingItemUrl('views/StartJourneyView');
        if (!$nextImageId) {
            header("Location: {$startJourneyUrl}");
            exit;
        }
        $dbConnection = DbConnectionUtil::getDbConnection();
        $nextImageData = ImageData::loadImageDataById($dbConnection, $nextImageId);
        if (!$nextImageData) {
            header("Location: {$startJourneyUrl}");
            exit;
        }
        parent::displayHeader($user, 'Journey');
        // attempt to parse the chosen attribute, if specified add to its tally
        if (isset($_GET[self::GET_PARAM_CHOSEN_ATTRIBUTE])) {
            $chosenAttribute = $_GET[self::GET_PARAM_CHOSEN_ATTRIBUTE];
            // verify the specified chosen attribute is actually an attribute of the chosen image
            if ($nextImageData->hasAttribute($chosenAttribute)) {
                if (!isset($_SESSION['JOURNEY_ATTRIBUTE_MAP'][$chosenAttribute])) {
                    $_SESSION['JOURNEY_ATTRIBUTE_MAP'][$chosenAttribute] = 1;
                } else {
                    $_SESSION['JOURNEY_ATTRIBUTE_MAP'][$chosenAttribute]++;
                }
            }
        }
        // store the current image id, in the journey session array, check for membership incase of a page re-load
        if (!in_array($nextImageId, $_SESSION['JOURNEY_IMAGE_LIST'])) {
            $_SESSION['JOURNEY_IMAGE_LIST'][] = $nextImageId;
        }
        $commonAttributeImageDataTupleList = NULL;
        $commonAttributeImageIdList = NULL;
        $randomImageDataList = NULL;
        // find NUM_SIMILAR_CHOICES common images if possible
        $commonAttributeImageIdTupleList = ImageAttribute::loadCommonAttributeImageIdTupleList($dbConnection, $nextImageId, $_SESSION['JOURNEY_IMAGE_LIST']);
        //print( "<br/>common id list: " ); print_r( $commonAttributeImageIdTupleList ); print("<br/>" );
        shuffle($commonAttributeImageIdTupleList);
        $commonAttributeImageIdList = array();
        $commonAttributeImageDataTupleList = array();
        while (count($commonAttributeImageDataTupleList) < self::NUM_SIMILAR_CHOICES && count($commonAttributeImageIdTupleList) > 0) {
            $currentEntry = array();
            $commonAttributeImageIdTuple = array_shift($commonAttributeImageIdTupleList);
            if (!in_array($commonAttributeImageIdTuple['imageId'], $commonAttributeImageDataTupleList) && !in_array($commonAttributeImageIdTuple['imageId'], $_SESSION['JOURNEY_IMAGE_LIST'])) {
                $imageData = ImageData::loadImageDataById($dbConnection, $commonAttributeImageIdTuple['imageId']);
                //print( "<br/>Image Data: " ); print_r( $imageData ); print( '<br/>' );
                $commonAttributeImageIdList[] = $commonAttributeImageIdTuple['imageId'];
                $currentEntry['imageData'] = $imageData;
                $currentEntry['attribute'] = $commonAttributeImageIdTuple['attribute'];
                $commonAttributeImageDataTupleList[] = $currentEntry;
            }
        }
        //print( "<br/>common map: " ); print_r( $commonAttributeImageDataTupleList ); print("<br/>" );
        // add a random image to the choices list, and fill in the gaps if NUM_SIMILAR_CHOICES could not be found, if possible
        /*
          print( "<br/>commonAttributeImageDataTupleList: " ); print_r( $commonAttributeImageDataTupleList ); print( "<br/>" );
          print( "allImageIdList: " ); print_r( $allImageIdList ); print( "<br/>" );
          print( "att_map: " ); print_r( $_SESSION['JOURNEY_IMAGE_LIST'] ); print( "<br/>" );
        */
        $allImageIdList = ImageData::loadAllImageIdList($dbConnection);
        shuffle($allImageIdList);
        $randomImageIdList = array();
        while (count($randomImageIdList) + count($commonAttributeImageIdList) < self::NUM_SIMILAR_CHOICES + 1 && count($allImageIdList) > 0) {
            $imageId = array_shift($allImageIdList);
            if ($imageId != $nextImageId && !in_array($imageId, $randomImageIdList) && !in_array($imageId, $commonAttributeImageIdList) && !in_array($imageId, $_SESSION['JOURNEY_IMAGE_LIST'])) {
                $randomImageIdList[] = $imageId;
            }
        }
        if (!empty($randomImageIdList)) {
            $randomImageDataList = ImageData::loadImageDataListByIdSet($dbConnection, $randomImageIdList);
        } else {
            $randomImageDataList = array();
        }
        // If the journey session array size has reached the number of journey steps, then set the is last
        // step flag to true, otherwise it should be false
        $IS_LAST_STEP = FALSE;
        if (count($_SESSION['JOURNEY_IMAGE_LIST']) == self::NUM_JOURNEY_STEPS) {
            $IS_LAST_STEP = TRUE;
        }
        // display the current image
        ?>
	<div class="currentJourneyImageSection">
	     <img src="<?php 
        echo UrlFormatter::formatImageUrl($nextImageData->getContentUri());
        ?>
"/>
	</div>
	<?php 
        // if this is not the last step, display further choices
        if (!$IS_LAST_STEP) {
            ?>
	    <p class="imageGridHeader">Choose Your Journey's Next Step</p>
	    <div class="centerWrapper">
	    <div class="imageGrid">
	    <?php 
            // list common choices
            foreach ($commonAttributeImageDataTupleList as $commonAttributeImageDataTuple) {
                $commonImageId = $commonAttributeImageDataTuple['imageData']->getId();
                $commonImageThumbUrl = UrlFormatter::formatImageUrl($commonAttributeImageDataTuple['imageData']->getThumbnailUri());
                $commonAttribute = $commonAttributeImageDataTuple['attribute'];
                $choiceUrl = UrlFormatter::formatRoutingItemUrl('views/JourneyStepView', array(self::GET_PARAM_NEXT_IMAGE_ID => $commonImageId, self::GET_PARAM_CHOSEN_ATTRIBUTE => $commonAttribute));
                ?>
		<a href="<?php 
                echo $choiceUrl;
                ?>
"><img src="<?php 
                echo $commonImageThumbUrl;
                ?>
"/></a>
		<?php 
            }
            // list random choices
            foreach ($randomImageDataList as $randomImageData) {
                $randomImageId = $randomImageData->getId();
                $thumbnailUrl = UrlFormatter::formatImageUrl($randomImageData->getThumbnailUri());
                $choiceUrl = UrlFormatter::formatRoutingItemUrl('views/JourneyStepView', array(self::GET_PARAM_NEXT_IMAGE_ID => $randomImageId));
                ?>
		<a href="<?php 
                echo $choiceUrl;
                ?>
"><img src="<?php 
                echo $thumbnailUrl;
                ?>
"/></a>
		<?php 
            }
            ?>
	    </div>
	    </div>
	    <?php 
        } else {
            $finishJourneyUrl = UrlFormatter::formatRoutingItemUrl('views/FinishJourneyView');
            ?>
	    <div class="finishJourneyButtonSection">
		 <a class="button" href="<?php 
            echo $finishJourneyUrl;
            ?>
">Finish Journey</a>
	    </div>
	    <?php 
        }
        parent::displayFooter();
    }
    public function processRequest(User $user = NULL)
    {
        parent::displayHeader($user, 'Start Journey');
        // TODO query for existing journeys
        // query for distinct image attributes
        $dbConnection = DbConnectionUtil::getDbConnection();
        $distinctAttributeList = ImageAttribute::loadExistingValues($dbConnection);
        // randomly select attributes, foreach attribute, retrieve the id of a unique image, store in sourceImageList
        shuffle($distinctAttributeList);
        $sourceImageIdList = array();
        for ($i = 0; $i < self::NUM_START_SELECTION_COUNT && count($distinctAttributeList) > 0; $i++) {
            $attribute = array_shift($distinctAttributeList);
            $imageIdList = ImageAttribute::loadImageIdListByAttribute($dbConnection, $attribute);
            shuffle($imageIdList);
            while (count($imageIdList) > 0) {
                $imageId = array_shift($imageIdList);
                if (!in_array($imageId, $sourceImageIdList)) {
                    $sourceImageIdList[] = $imageId;
                    break;
                }
            }
        }
        // if the full number of starting images could not be found with distinct attributes, then randomly select more to fill in the gap
        if (count($sourceImageIdList) < self::NUM_START_SELECTION_COUNT) {
            $allImageIdList = ImageData::loadAllImageIdList($dbConnection);
            shuffle($allImageIdList);
            while (count($sourceImageIdList) < self::NUM_START_SELECTION_COUNT && count($allImageIdList) > 0) {
                $imageId = array_shift($allImageIdList);
                if (!in_array($imageId, $sourceImageIdList)) {
                    $sourceImageIdList[] = $imageId;
                }
            }
        }
        // load the randomly selected images
        $sourceImageDataList = ImageData::loadImageDataListByIdSet($dbConnection, $sourceImageIdList);
        shuffle($sourceImageDataList);
        // reset the journey's session data
        if (isset($_SESSION['JOURNEY_IMAGE_LIST'])) {
            unset($_SESSION['JOURNEY_IMAGE_LIST']);
        }
        $_SESSION['JOURNEY_IMAGE_LIST'] = array();
        if (isset($_SESSION['JOURNEY_ATTRIBUTE_MAP'])) {
            unset($_SESSION['JOURNEY_ATTRIBUTE_MAP']);
        }
        $_SESSION['JOURNEY_ATTRIBUTE_MAP'] = array();
        ?>
	<p class="imageGridHeader">Choose Your Journey's Starting Image</p>
	<div class="centerWrapper">
	<div class="imageGrid">	     
             <?php 
        foreach ($sourceImageDataList as $imageData) {
            $imageJourneyUrl = UrlFormatter::formatRoutingItemUrl('views/JourneyStepView', array(JourneyStepView::GET_PARAM_NEXT_IMAGE_ID => $imageData->getId()));
            $imageThumbUrl = UrlFormatter::formatImageUrl($imageData->getThumbnailUri());
            ?>
		 <a href="<?php 
            echo $imageJourneyUrl;
            ?>
"> <img src="<?php 
            echo $imageThumbUrl;
            ?>
"></a>
		 <?php 
        }
        ?>
	</div>
	</div>
	<?php 
        // TODO display a list of existing journeys
        parent::displayFooter();
    }
 protected static function formatImageAttributeDataAutoComplete(PDO $dbConnection, $inputDOMId)
 {
     $existingFieldValueList = ImageAttribute::loadExistingValues($dbConnection);
     self::generateAutoCompleteScript($existingFieldValueList, $inputDOMId);
 }
 /**
  * This is a private helper function for populating an ImageData obejct given
  * the specified DB result row.
  * @param int $imageId The DB id of the image being populated.
  * @param array $resultRow The DB query result row this function will consume data from.
  * @return ImageData A populated image data object.
  */
 private static function populateImageDataByDbResultRow(array $resultRow, PDO $dbConnection)
 {
     $imageData = new ImageData($resultRow['id']);
     $imageData->setContentUri($resultRow['content_uri']);
     $imageData->setSubmitterUserId($resultRow['submitter_user_id']);
     $imageData->setThumbnailUri($resultRow['thumbnail_uri']);
     $imageData->setAuthor($resultRow['author']);
     $imageData->setTitle($resultRow['title']);
     $imageData->setYear($resultRow['year']);
     $imageData->setAttributeList(ImageAttribute::loadImageAttributeListByImageDataId($dbConnection, $imageData->getId()));
     return $imageData;
 }