<?php

class ApiController extends Zend_Controller_Action
{

    public function init()
    {
        /* Initialize action controller here */
        $context = $this->_helper->getHelper('contextSwitch');
        $context->addActionContext('version', 'json')
                ->addActionContext('recorded-shows', 'json')
                ->addActionContext('server-timestamp', 'json')
                ->addActionContext('upload-file', 'json')
                ->addActionContext('upload-recorded', 'json')
                ->addActionContext('media-monitor-setup', 'json')
                ->addActionContext('media-item-status', 'json')
                ->addActionContext('reload-metadata', 'json')
                ->addActionContext('list-all-files', 'json')
                ->addActionContext('list-all-watched-dirs', 'json')
                ->addActionContext('add-watched-dir', 'json')
                ->addActionContext('remove-watched-dir', 'json')
                ->addActionContext('set-storage-dir', 'json')
                ->addActionContext('get-stream-setting', 'json')
                ->addActionContext('status', 'json')
                ->addActionContext('register-component', 'json')
                ->initContext();
    }

    public function indexAction()
    {
        // action body
    }

    /**
     * Returns Airtime version. i.e "1.7.0-beta"
     *
     * First checks to ensure the correct API key was
     * supplied, then returns AIRTIME_VERSION as defined
     * in the database
     *
     * @return void
     *
     */
    public function versionAction()
    {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }
        $jsonStr = json_encode(array("version"=>Application_Model_Preference::GetAirtimeVersion()));
        echo $jsonStr;
    }
    
    public function serverTimestampAction(){
    
        $this->view->serverTimestamp = array("timestamp"=>time(), "timezoneOffset"=> date("Z"));
    
    }

    /**
     * Allows remote client to download requested media file.
     *
     * @return void
     *
     */
    public function getMediaAction()
    {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');
        $download = ("true" == $this->_getParam('download'));

        $logger = Logging::getLogger();

        if(!in_array($api_key, $CC_CONFIG["apiKey"]) &&
            is_null(Zend_Auth::getInstance()->getStorage()->read()))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            $logger->info("401 Unauthorized");
            return;
        }

        $filename = $this->_getParam("file");
        $file_id = substr($filename, 0, strpos($filename, "."));
        if (ctype_alnum($file_id) && strlen($file_id) == 32) {
          $media = Application_Model_StoredFile::RecallByGunid($file_id);
          if ($media != null && !PEAR::isError($media)) {
            $filepath = $media->getFilePath();
            if(is_file($filepath)){
                // possibly use fileinfo module here in the future.
                // http://www.php.net/manual/en/book.fileinfo.php
                $ext = pathinfo($filename, PATHINFO_EXTENSION);
                if ($ext == "ogg")
                    header("Content-Type: audio/ogg");
                else if ($ext == "mp3")
                    header("Content-Type: audio/mpeg");
                if ($download){
                    //path_info breaks up a file path into seperate pieces of informaiton.
                    //We just want the basename which is the file name with the path
                    //information stripped away. We are using Content-Disposition to specify
                    //to the browser what name the file should be saved as.
                    //
                    // By james.moon:
                    // I'm removing pathinfo() since it strips away UTF-8 characters.
                    // Using manualy parsing
                    $full_path = $media->getPropelOrm()->getDbFilepath();
                    $file_base_name = strrchr($full_path, '/');
                    $file_base_name = substr($file_base_name, 1);
                    header('Content-Disposition: attachment; filename="'.$file_base_name.'"');
                }
                $logger->info("Sending $filepath");
                header("Content-Length: " . filesize($filepath));

                // !! binary mode !!
                $fp = fopen($filepath, 'rb');

                //We can have multiple levels of output buffering. Need to
                //keep looping until all have been disabled!!!
                //http://www.php.net/manual/en/function.ob-end-flush.php
                while (@ob_end_flush());

                fpassthru($fp);
                fclose($fp);

                //make sure to exit here so that no other output is sent.
                exit;
            } else {
                $logger->err('Resource in database, but not in storage: "'.$filepath.'"');
            }
          } else {
            $logger->err('$media != null && !PEAR::isError($media)');
          }
      } else {
        $logger->err('ctype_alnum($file_id) && strlen($file_id) == 32');
      }
      header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
      $logger->info("404 Not Found");
      return;
    }

    public function liveInfoAction()
    {
        if (Application_Model_Preference::GetAllow3rdPartyApi()){
            // disable the view and the layout
            $this->view->layout()->disableLayout();
            $this->_helper->viewRenderer->setNoRender(true);

            $date = new Application_Model_DateHelper;
            $timeNow = $date->getTimestamp();
            $result = array("env"=>APPLICATION_ENV,
                "schedulerTime"=>gmdate("Y-m-d H:i:s"),
                "currentShow"=>Application_Model_Show::GetCurrentShow($timeNow),
                "nextShow"=>Application_Model_Show::GetNextShows($timeNow, 5),
                "timezone"=> date("T"),
                "timezoneOffset"=> date("Z"));

            //echo json_encode($result);
            header("Content-type: text/javascript");
            echo $_GET['callback'].'('.json_encode($result).')';
        } else {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource. ';
            exit;
        }
    }

    public function weekInfoAction()
    {
        if (Application_Model_Preference::GetAllow3rdPartyApi()){
            // disable the view and the layout
            $this->view->layout()->disableLayout();
            $this->_helper->viewRenderer->setNoRender(true);

            $dow = array("sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday");

            $result = array();
            for ($i=0; $i<7; $i++){
                $result[$dow[$i]] = Application_Model_Show::GetShowsByDayOfWeek($i);
            }

            header("Content-type: text/javascript");
            echo $_GET['callback'].'('.json_encode($result).')';
        } else {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource. ';
            exit;
        }
    }

    public function scheduleAction()
    {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');

        if(!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource. ';
            exit;
        }

        PEAR::setErrorHandling(PEAR_ERROR_RETURN);

        $result = Application_Model_Schedule::GetScheduledPlaylists();
        echo json_encode($result);
    }

    public function notifyMediaItemStartPlayAction()
    {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');
        if(!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $schedule_group_id = $this->_getParam("schedule_id");
        $media_id = $this->_getParam("media_id");
        $result = Application_Model_Schedule::UpdateMediaPlayedStatus($media_id);

        if (!PEAR::isError($result)) {
            echo json_encode(array("status"=>1, "message"=>""));
        } else {
            echo json_encode(array("status"=>0, "message"=>"DB Error:".$result->getMessage()));
        }
    }

    public function notifyScheduleGroupPlayAction()
    {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');
        if(!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        PEAR::setErrorHandling(PEAR_ERROR_RETURN);

        $schedule_group_id = $this->_getParam("schedule_id");
        if (is_numeric($schedule_group_id)) {
            $sg = new Application_Model_ScheduleGroup($schedule_group_id);
            if ($sg->exists()) {
                $result = $sg->notifyGroupStartPlay();
                if (!PEAR::isError($result)) {
                    echo json_encode(array("status"=>1, "message"=>""));
                    exit;
                } else {
                    echo json_encode(array("status"=>0, "message"=>"DB Error:".$result->getMessage()));
                    exit;
                }
            } else {
                echo json_encode(array("status"=>0, "message"=>"Schedule group does not exist: ".$schedule_group_id));
                exit;
            }
        } else {
            echo json_encode(array("status"=>0, "message"=>"Incorrect or non-numeric arguments given."));
            exit;
        }
    }

    public function recordedShowsAction()
    {
        global $CC_CONFIG;

        $api_key = $this->_getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $today_timestamp = date("Y-m-d H:i:s");
        $now = new DateTime($today_timestamp);
        $end_timestamp = $now->add(new DateInterval("PT2H"));
        $end_timestamp = $end_timestamp->format("Y-m-d H:i:s");
        $this->view->shows = Application_Model_Show::getShows($today_timestamp, $end_timestamp, $excludeInstance=NULL, $onlyRecord=TRUE);


        $this->view->is_recording = false;

        $rows = Application_Model_Show::GetCurrentShow($today_timestamp);
        if (count($rows) > 0){
            $this->view->is_recording = ($rows[0]['record'] == 1);
        }
    }

    public function uploadFileAction()
    {
        global $CC_CONFIG;

        $api_key = $this->_getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $upload_dir = ini_get("upload_tmp_dir");
        Application_Model_StoredFile::uploadFile($upload_dir);
        $fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : '';
        Application_Model_StoredFile::copyFileToStor($upload_dir, $fileName);
    }

    public function uploadRecordedAction()
    {
        global $CC_CONFIG;

        $api_key = $this->_getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        //this file id is the recording for this show instance.
        $show_instance_id = $this->_getParam('showinstanceid');
        $file_id = $this->_getParam('fileid');

        $this->view->fileid = $file_id;
        $this->view->showinstanceid = $show_instance_id;


       	$showCanceled = false;
       	$file = Application_Model_StoredFile::Recall($file_id);
        //$show_instance  = $this->_getParam('show_instance');

        $show_name = null;
        try {
            $show_inst = new Application_Model_ShowInstance($show_instance_id);

            $show_inst->setRecordedFile($file_id);
            $show_name = $show_inst->getName();
            $show_genre = $show_inst->getGenre();
            $show_start_time = ConvertToLocalDateTimeString($show_inst->getShowStart());

         } catch (Exception $e){
            //we've reached here probably because the show was
            //cancelled, and therefore the show instance does not
            //exist anymore (ShowInstance constructor threw this error).
            //We've done all we can do (upload the file and put it in
            //the library), now lets just return.
            $showCanceled = true;
        }

        if (isset($show_name)) {
            $tmpTitle = "$show_name-$show_start_time";
            $tmpTitle = str_replace(" ", "-", $tmpTitle);
        }
        else {
            $tmpTitle = $file->getName();
        }

		$file->setMetadataValue('MDATA_KEY_TITLE', $tmpTitle);
        $file->setMetadataValue('MDATA_KEY_CREATOR', "Airtime Show Recorder");
        $file->setMetadataValue('MDATA_KEY_TRACKNUMBER', null);

        if (!$showCanceled && Application_Model_Preference::GetAutoUploadRecordedShowToSoundcloud())
        {
        	for ($i=0; $i<$CC_CONFIG['soundcloud-connection-retries']; $i++) {

        		$show = new Application_Model_Show($show_inst->getShowId());
        		$description = $show->getDescription();
        		$hosts = $show->getHosts();

        		$tags = array_merge($hosts, array($show_name));

        		try {
        			$soundcloud = new Application_Model_Soundcloud();
        			$soundcloud_id = $soundcloud->uploadTrack($file->getFilePath(), $tmpTitle, $description, $tags, $show_start_time, $show_genre);
        			$file->setSoundCloudFileId($soundcloud_id);
        			break;
        		}
        		catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) {
        			$code = $e->getHttpCode();
                    $msg = $e->getHttpBody();
                    $temp = explode('"error":',$msg);
                    $msg = trim($temp[1], '"}');
                    $this->setSoundCloudErrorCode($code);
                    $this->setSoundCloudErrorMsg($msg);
                    // setting sc id to -3 which indicates error
                    $this->setSoundCloudFileId(SOUNDCLOUD_ERROR);
        			if(!in_array($code, array(0, 100))) {
        				break;
        			}
        		}

        		sleep($CC_CONFIG['soundcloud-connection-wait']);
        	}
        }

        $this->view->id = $file_id;

    }

    public function mediaMonitorSetupAction() {
        global $CC_CONFIG;

        // disable the view and the layout
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $api_key = $this->_getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $this->view->stor = Application_Model_MusicDir::getStorDir()->getDirectory();
        
        $watchedDirs = Application_Model_MusicDir::getWatchedDirs();
        $watchedDirsPath = array();
        foreach($watchedDirs as $wd){
            $watchedDirsPath[] = $wd->getDirectory();
        }
        $this->view->watched_dirs = $watchedDirsPath;
    }

    public function reloadMetadataAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $mode = $request->getParam('mode');
        $params = $request->getParams();

        $md = array();
        //extract all file metadata params from the request.
        foreach ($params as $key => $value) {
            if (preg_match('/^MDATA_KEY/', $key)) {
                $md[$key] = $value;
            }
        }

        // update import timestamp
        Application_Model_Preference::SetImportTimestamp();
        
        if ($mode == "create") {
            $filepath = $md['MDATA_KEY_FILEPATH'];
            $filepath = str_replace("\\", "", $filepath);

            $file = Application_Model_StoredFile::RecallByFilepath($filepath);

            if (is_null($file)) {
                $file = Application_Model_StoredFile::Insert($md);
            }
            else {
                $this->view->error = "File already exists in Airtime.";
                return;
            }
        }
        else if ($mode == "modify") {
            $filepath = $md['MDATA_KEY_FILEPATH'];
            $filepath = str_replace("\\", "", $filepath);
            $file = Application_Model_StoredFile::RecallByFilepath($filepath);

            //File is not in database anymore.
            if (is_null($file)) {
                $this->view->error = "File does not exist in Airtime.";
                return;
            }
            //Updating a metadata change.
            else {
                $file->setMetadata($md);
            }
        }
        else if ($mode == "moved") {
            $md5 = $md['MDATA_KEY_MD5'];
            $file = Application_Model_StoredFile::RecallByMd5($md5);

            if (is_null($file)) {
                $this->view->error = "File doesn't exist in Airtime.";
                return;
            }
            else {
                $filepath = $md['MDATA_KEY_FILEPATH'];
                $filepath = str_replace("\\", "", $filepath);
                $file->setFilePath($filepath);
                //$file->setMetadata($md);
            }
        }
        else if ($mode == "delete") {
            $filepath = $md['MDATA_KEY_FILEPATH'];
            $filepath = str_replace("\\", "", $filepath);
            $file = Application_Model_StoredFile::RecallByFilepath($filepath);

            if (is_null($file)) {
                $this->view->error = "File doesn't exist in Airtime.";
                return;
            }
            else {
                $file->delete();
            }
        }
        else if ($mode == "delete_dir") {
            $filepath = $md['MDATA_KEY_FILEPATH'];
            $filepath = str_replace("\\", "", $filepath);
            $files = Application_Model_StoredFile::RecallByPartialFilepath($filepath);

            foreach($files as $file){
                $file->delete();
            }
            return;
        }
        $this->view->id = $file->getId();
    }

    public function listAllFilesAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }
        $dir_id = $request->getParam('dir_id');

        $this->view->files = Application_Model_StoredFile::listAllFiles($dir_id);
    }

    public function listAllWatchedDirsAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $result = array();

        $arrWatchedDirs = Application_Model_MusicDir::getWatchedDirs();
        $storDir = Application_Model_MusicDir::getStorDir();

        $result[$storDir->getId()] = $storDir->getDirectory();

        foreach ($arrWatchedDirs as $watchedDir){
            $result[$watchedDir->getId()] = $watchedDir->getDirectory();
        }

        $this->view->dirs = $result;
    }

    public function addWatchedDirAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        $path = base64_decode($request->getParam('path'));

        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $this->view->msg = Application_Model_MusicDir::addWatchedDir($path);
    }

    public function removeWatchedDirAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        $path = base64_decode($request->getParam('path'));

        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $this->view->msg = Application_Model_MusicDir::removeWatchedDir($path);
    }

    public function setStorageDirAction() {
        global $CC_CONFIG;

        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        $path = base64_decode($request->getParam('path'));

        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $this->view->msg = Application_Model_MusicDir::setStorDir($path);
    }
    
    public function getStreamSettingAction() {
        global $CC_CONFIG;
        
        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }

        $this->view->msg = Application_Model_StreamSetting::getStreamSetting();
    }
    
    public function statusAction() {
        global $CC_CONFIG;
        
        $request = $this->getRequest();
        $api_key = $request->getParam('api_key');
        /*
        if (!in_array($api_key, $CC_CONFIG["apiKey"]))
        {
            header('HTTP/1.0 401 Unauthorized');
            print 'You are not allowed to access this resource.';
            exit;
        }
        */
        
        $status = array(
            "platform"=>Application_Model_Systemstatus::GetPlatformInfo(),
            "airtime_version"=>Application_Model_Preference::GetAirtimeVersion(),
            "services"=>array(
                "rabbitmq"=>Application_Model_Systemstatus::GetRabbitMqStatus(),
                "pypo"=>Application_Model_Systemstatus::GetPypoStatus(),
                "liquidsoap"=>Application_Model_Systemstatus::GetLiquidsoapStatus(),
                "show_recorder"=>Application_Model_Systemstatus::GetShowRecorderStatus(),
                "media_monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus()
            ),
            "partitions"=>Application_Model_Systemstatus::GetDiskInfo()
        );
        
        $this->view->status = $status;
    }

    public function registerComponentAction(){
        $request = $this->getRequest();

        $component = $request->getParam('component');
        $remoteAddr = $_SERVER['REMOTE_ADDR'];
        Logging::log("Registered Component: ".$component."@".$remoteAddr);

        Application_Model_ServiceRegister::Register($component, $remoteAddr);
    }
}