<?php

class PreferenceController extends Zend_Controller_Action
{

    public function init()
    {
        /* Initialize action controller here */
        $ajaxContext = $this->_helper->getHelper('AjaxContext');
        $ajaxContext->addActionContext('server-browse', 'json')
                    ->addActionContext('change-stor-directory', 'json')
                    ->addActionContext('reload-watch-directory', 'json')
                    ->addActionContext('remove-watch-directory', 'json')
                    ->addActionContext('is-import-in-progress', 'json')
                    ->addActionContext('change-stream-setting', 'json')
                    ->addActionContext('get-liquidsoap-status', 'json')
                    ->addActionContext('set-source-connection-url', 'json')
                    ->addActionContext('get-admin-password-status', 'json')
                    ->initContext();
    }

    public function indexAction()
    {
        $CC_CONFIG = Config::getConfig();
        $request = $this->getRequest();

        Zend_Layout::getMvcInstance()->assign('parent_page', 'Settings');

        $baseUrl = Application_Common_OsPath::getBaseDir();

        $this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/preferences.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
        $this->view->statusMsg = "";

        $form = new Application_Form_Preferences();
        $values = array();

        SessionHelper::reopenSessionForWriting();

        if ($request->isPost()) {
            $values = $request->getPost();
            if ($form->isValid($values))
            {
                Application_Model_Preference::SetHeadTitle($values["stationName"], $this->view);
                Application_Model_Preference::SetStationDescription($values["stationDescription"]);
                Application_Model_Preference::SetTrackTypeDefault($values["tracktypeDefault"]);
                Application_Model_Preference::SetDefaultCrossfadeDuration($values["stationDefaultCrossfadeDuration"]);
                Application_Model_Preference::SetDefaultFadeIn($values["stationDefaultFadeIn"]);
                Application_Model_Preference::SetDefaultFadeOut($values["stationDefaultFadeOut"]);
                Application_Model_Preference::SetPodcastAlbumOverride($values["podcastAlbumOverride"]);
                Application_Model_Preference::SetPodcastAutoSmartblock($values["podcastAutoSmartblock"]);
                Application_Model_Preference::SetIntroPlaylist($values["introPlaylistSelect"]);
                Application_Model_Preference::SetOutroPlaylist($values["outroPlaylistSelect"]);
                Application_Model_Preference::SetAllow3rdPartyApi($values["thirdPartyApi"]);
                Application_Model_Preference::SetAllowedCorsUrls($values["allowedCorsUrls"]);
                Application_Model_Preference::SetDefaultLocale($values["locale"]);
                Application_Model_Preference::SetDefaultTimezone($values["timezone"]);
                Application_Model_Preference::SetWeekStartDay($values["weekStartDay"]);
                Application_Model_Preference::setRadioPageDisplayLoginButton($values["radioPageLoginButton"]);
                Application_Model_Preference::SetFeaturePreviewMode($values["featurePreviewMode"]);

                $logoUploadElement = $form->getSubForm('preferences_general')->getElement('stationLogo');
                $logoUploadElement->receive();
                $imagePath = $logoUploadElement->getFileName();

                // Only update the image logo if the new logo is non-empty
                if (!empty($imagePath) && $imagePath != "") {
                    Application_Model_Preference::SetStationLogo($imagePath);
                }

                Application_Model_Preference::setTuneinEnabled($values["enable_tunein"]);
                Application_Model_Preference::setTuneinStationId($values["tunein_station_id"]);
                Application_Model_Preference::setTuneinPartnerKey($values["tunein_partner_key"]);
                Application_Model_Preference::setTuneinPartnerId($values["tunein_partner_id"]);

                $this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
                $form = new Application_Form_Preferences();
                $this->view->form = $form;
                //$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml')));
            } else {
                $this->view->form = $form;
                //$this->_helper->json->sendJson(array("valid"=>"false", "html"=>$this->view->render('preference/index.phtml')));
            }
        }
        $this->view->logoImg = Application_Model_Preference::GetStationLogo();

        $this->view->form = $form;
    }

    public function stationPodcastSettingsAction() {
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        $values = json_decode($this->getRequest()->getRawBody());

        if (!Application_Model_Preference::getStationPodcastPrivacy() && $values->stationPodcastPrivacy == 1) {
            // Refresh the download key when enabling privacy
            Application_Model_Preference::setStationPodcastDownloadKey();
        }

        // Append sharing token (download key) to Station podcast URL
        $stationPodcast = PodcastQuery::create()->findOneByDbId(Application_Model_Preference::getStationPodcastId());
        $key = Application_Model_Preference::getStationPodcastDownloadKey();
        $url = Application_Common_HTTPHelper::getStationUrl() .
            (((int) $values->stationPodcastPrivacy) ? "feeds/station-rss?sharing_token=$key" : "feeds/station-rss");
        $stationPodcast->setDbUrl($url)->save();
        Application_Model_Preference::setStationPodcastPrivacy($values->stationPodcastPrivacy);

        $this->_helper->json->sendJson(array("url" => $url));
    }

    public function directoryConfigAction()
    {
    }

    public function removeLogoAction()
    {
        SessionHelper::reopenSessionForWriting();

        $this->view->layout()->disableLayout();
        // Remove reliance on .phtml files to render requests
        $this->_helper->viewRenderer->setNoRender(true);

        if (!SecurityHelper::verifyCSRFToken($this->_getParam('csrf_token'))) {
            Logging::error(__FILE__ . ': Invalid CSRF token');
            $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "valid" => false, "error" => "CSRF token did not match."));
            return;
        }

        Application_Model_Preference::SetStationLogo("");
    }

    public function streamSettingAction()
    {
        $CC_CONFIG = Config::getConfig();

        $request = $this->getRequest();

        Zend_Layout::getMvcInstance()->assign('parent_page', 'Settings');

        $baseUrl = Application_Common_OsPath::getBaseDir();

        $this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');

        SessionHelper::reopenSessionForWriting();

        $name_map = array(
				'ogg' => 'Ogg Vorbis',
                'fdkaac' => 'AAC+',
                'aac' => 'AAC',
                'opus' => 'Opus',
                'mp3' => 'MP3',
        );

        $num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
        $form = new Application_Form_StreamSetting();

        $csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
        $csrf_element = new Zend_Form_Element_Hidden('csrf');
        $csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label');
        $form->addElement($csrf_element);

        $live_stream_subform = new Application_Form_LiveStreamingPreferences();
        $form->addSubForm($live_stream_subform, "live_stream_subform");

        // get predefined type and bitrate from pref table
        $temp_types = Application_Model_Preference::GetStreamType();
        $stream_types = array();
        foreach ($temp_types as $type) {
            $type = strtolower(trim($type));
            if (isset($name_map[$type])) {
                $name = $name_map[$type];
            } else {
                $name = $type;
            }
            $stream_types[$type] = $name;
        }

        $temp_bitrate = Application_Model_Preference::GetStreamBitrate();
        $max_bitrate = intval(Application_Model_Preference::GetMaxBitrate());
        $stream_bitrates = array();
        foreach ($temp_bitrate as $type) {
            if (intval($type) <= $max_bitrate) {
                $stream_bitrates[trim($type)] = strtoupper(trim($type))." kbit/s";
            }
        }

        // get current settings
        $setting = Application_Model_StreamSetting::getStreamSetting();
        $form->setSetting($setting);

        for ($i=1; $i<=$num_of_stream; $i++) {
            $subform = new Application_Form_StreamSettingSubForm();
            $subform->setPrefix($i);
            $subform->setSetting($setting);
            $subform->setStreamTypes($stream_types);
            $subform->setStreamBitrates($stream_bitrates);
            $subform->startForm();
            $subform->toggleState();
            $form->addSubForm($subform, "s".$i."_subform");
        }

        $live_stream_subform->updateVariables();
        $form->startFrom();

        if ($request->isPost()) {
            $params = $request->getPost();
            /* Parse through post data and put in format
             * $form->isValid() is expecting it in
             */
            $postData = explode('&', $params['data']);
            $s1_data = array();
            $s2_data = array();
            $s3_data = array();
            $s4_data = array();
            $values = array();
            foreach($postData as $k=>$v) {
                $v = explode('=', urldecode($v));
                if (strpos($v[0], "s1_data") !== false) {
                    /* In this case $v[0] may be 's1_data[enable]' , for example.
                     * We only want the 'enable' part
                     */
                    preg_match('/\[(.*)\]/', $v[0], $matches);
                    $s1_data[$matches[1]] = $v[1];
                } elseif (strpos($v[0], "s2_data") !== false) {
                    preg_match('/\[(.*)\]/', $v[0], $matches);
                    $s2_data[$matches[1]] = $v[1];
                } elseif (strpos($v[0], "s3_data") !== false) {
                   preg_match('/\[(.*)\]/', $v[0], $matches);
                    $s3_data[$matches[1]] = $v[1];
                } elseif (strpos($v[0], "s4_data") !== false) {
                   preg_match('/\[(.*)\]/', $v[0], $matches);
                    $s4_data[$matches[1]] = $v[1];
                } else {
                    $values[$v[0]] = $v[1];
                }
            }
            $values["s1_data"] = $s1_data;
            $values["s2_data"] = $s2_data;
            $values["s3_data"] = $s3_data;
            $values["s4_data"] = $s4_data;

            if ($form->isValid($values)) {
                Application_Model_StreamSetting::setStreamSetting($values);

                /* If the admin password values are empty then we should not
                 * set the pseudo password ('xxxxxx') on the front-end
                 */
                $s1_set_admin_pass = !empty($values["s1_data"]["admin_pass"]);
                $s2_set_admin_pass = !empty($values["s2_data"]["admin_pass"]);
                $s3_set_admin_pass = !empty($values["s3_data"]["admin_pass"]);
                $s4_set_admin_pass = !empty($values["s4_data"]["admin_pass"]);

                // this goes into cc_pref table
                $this->setStreamPreferences($values);

                // compare new values with current value
                $changeRGenabled = Application_Model_Preference::GetEnableReplayGain() != $values["enableReplayGain"];
                $changeRGmodifier = Application_Model_Preference::getReplayGainModifier() != $values["replayGainModifier"];
                if ($changeRGenabled || $changeRGmodifier) {
                    Application_Model_Preference::SetEnableReplayGain($values["enableReplayGain"]);
                    Application_Model_Preference::setReplayGainModifier($values["replayGainModifier"]);
                    $md = array('schedule' => Application_Model_Schedule::getSchedule());
                    Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md);
                    //Application_Model_RabbitMq::PushSchedule();
                }

                // pulling this from the 2.5.x branch
                if (!Application_Model_Preference::GetMasterDjConnectionUrlOverride()) {
                    $master_connection_url = "http://".$_SERVER['SERVER_NAME'].":".$values["master_source_port"].$values["master_source_mount"];
                    if (empty($values["master_source_port"]) || empty($values["master_source_mount"])) {
                        Application_Model_Preference::SetMasterDJSourceConnectionURL('N/A');
                    } else {
                        Application_Model_Preference::SetMasterDJSourceConnectionURL($master_connection_url);
                    }
                } else {
                    Application_Model_Preference::SetMasterDJSourceConnectionURL($values["master_source_host"]);
                }

                if (!Application_Model_Preference::GetLiveDjConnectionUrlOverride()) {
                    $live_connection_url = "http://".$_SERVER['SERVER_NAME'].":".$values["show_source_port"].$values["show_source_mount"];
                    if (empty($values["show_source_port"]) || empty($values["show_source_mount"])) {
                        Application_Model_Preference::SetLiveDJSourceConnectionURL('N/A');
                    } else {
                        Application_Model_Preference::SetLiveDJSourceConnectionURL($live_connection_url);
                    }
                } else {
                    Application_Model_Preference::SetLiveDJSourceConnectionURL($values["show_source_host"]);
                }


                Application_Model_StreamSetting::setMasterLiveStreamPort($values["master_source_port"]);
                Application_Model_StreamSetting::setMasterLiveStreamMountPoint($values["master_source_mount"]);
                Application_Model_StreamSetting::setDjLiveStreamPort($values["show_source_port"]);
                Application_Model_StreamSetting::setDjLiveStreamMountPoint($values["show_source_mount"]);

                Application_Model_StreamSetting::setOffAirMeta($values['offAirMeta']);

                // store stream update timestamp
                Application_Model_Preference::SetStreamUpdateTimestamp();

                $data = array();
                $info = Application_Model_StreamSetting::getStreamSetting();
                $data['setting'] = $info;
                for ($i=1; $i<=$num_of_stream; $i++) {
                    Application_Model_StreamSetting::setLiquidsoapError($i, "waiting");
                }

                Application_Model_RabbitMq::SendMessageToPypo("update_stream_setting", $data);
                $this->view->statusMsg = "<div class='success'>"._("Stream Setting Updated.")."</div>";
            }
        }

        $this->view->num_stream = $num_of_stream;
        $this->view->enable_stream_conf = Application_Model_Preference::GetEnableStreamConf();
        $this->view->form = $form;
        if ($request->isPost()) {
            if ($form->isValid($values)) {
                $this->_helper->json->sendJson(array(
                                                   "valid" => "true",
                                                   "html" => $this->view->render('preference/stream-setting.phtml'),
                                                   "s1_set_admin_pass" => $s1_set_admin_pass,
                                                   "s2_set_admin_pass" => $s2_set_admin_pass,
                                                   "s3_set_admin_pass" => $s3_set_admin_pass,
                                                   "s4_set_admin_pass" => $s4_set_admin_pass,
                                               ));
            } else {
                $this->_helper->json->sendJson(array("valid" => "false", "html" => $this->view->render('preference/stream-setting.phtml')));
            }
        }
    }

    /**
     * Set stream settings preferences
     *
     * @param array $values stream setting preference values
     */
    private function setStreamPreferences($values) {
        Application_Model_Preference::setUsingCustomStreamSettings($values['customStreamSettings']);
        Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
        Application_Model_Preference::SetLiveStreamMasterUsername($values["master_username"]);
        Application_Model_Preference::SetLiveStreamMasterPassword($values["master_password"]);
        Application_Model_Preference::SetDefaultTransitionFade($values["transition_fade"]);
        Application_Model_Preference::SetAutoTransition($values["auto_transition"]);
        Application_Model_Preference::SetAutoSwitch($values["auto_switch"]);

    }

    public function serverBrowseAction()
    {
        $request = $this->getRequest();
        $path = $request->getParam("path", null);

        $result = array();

        if (is_null($path)) {
            $element = array();
            $element["name"] = _("path should be specified");
            $element["isFolder"] = false;
            $element["isError"] = true;
            $result[$path] = $element;
        } else {
            $path = $path.'/';
            $handle = opendir($path);
            if ($handle !== false) {
                while (false !== ($file = readdir($handle))) {
                    if ($file != "." && $file != "..") {
                        //only show directories that aren't private.
                        if (is_dir($path.$file) && substr($file, 0, 1) != ".") {
                            $element = array();
                            $element["name"] = $file;
                            $element["isFolder"] = true;
                            $element["isError"] = false;
                            $result[$file] = $element;
                        }
                    }
                }
            }
        }
        ksort($result);
        //returns format serverBrowse is looking for.
        $this->_helper->json->sendJson($result);
    }

    public function changeStorDirectoryAction()
    {
        $chosen = $this->getRequest()->getParam("dir");
        $element = $this->getRequest()->getParam("element");
        $watched_dirs_form = new Application_Form_WatchedDirPreferences();

        $res = Application_Model_MusicDir::setStorDir($chosen);
        if ($res['code'] != 0) {
            $watched_dirs_form->populate(array('storageFolder' => $chosen));
            $watched_dirs_form->getElement($element)->setErrors(array($res['error']));
        }

        $this->view->subform = $watched_dirs_form->render();
    }

    public function reloadWatchDirectoryAction()
    {
        $chosen = $this->getRequest()->getParam("dir");
        $element = $this->getRequest()->getParam("element");
        $watched_dirs_form = new Application_Form_WatchedDirPreferences();

        $res = Application_Model_MusicDir::addWatchedDir($chosen);
        if ($res['code'] != 0) {
            $watched_dirs_form->populate(array('watchedFolder' => $chosen));
            $watched_dirs_form->getElement($element)->setErrors(array($res['error']));
        }

        $this->view->subform = $watched_dirs_form->render();
    }

    public function rescanWatchDirectoryAction()
    {
        $dir_path = $this->getRequest()->getParam('dir');
        $dir = Application_Model_MusicDir::getDirByPath($dir_path);
        $data = array( 'directory' => $dir->getDirectory(),
                              'id' => $dir->getId());
        Application_Model_RabbitMq::SendMessageToMediaMonitor('rescan_watch', $data);
        Logging::info("Unhiding all files belonging to:: $dir_path");
        $dir->unhideFiles();
        $this->_helper->json->sendJson(null);
    }

    public function removeWatchDirectoryAction()
    {
        $chosen = $this->getRequest()->getParam("dir");

        $dir = Application_Model_MusicDir::removeWatchedDir($chosen);

        $watched_dirs_form = new Application_Form_WatchedDirPreferences();
        $this->view->subform = $watched_dirs_form->render();
    }

    public function isImportInProgressAction()
    {
        $now = time();
        $res = false;
        if (Application_Model_Preference::GetImportTimestamp()+10 > $now) {
            $res = true;
        }
        $this->_helper->json->sendJson($res);
    }

    public function getLiquidsoapStatusAction()
    {
        $out = array();
        $num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
        for ($i=1; $i<=$num_of_stream; $i++) {
            $status = Application_Model_StreamSetting::getLiquidsoapError($i);
            $status = $status == NULL?_("Problem with Liquidsoap..."):$status;
            if (!Application_Model_StreamSetting::getStreamEnabled($i)) {
                $status = "N/A";
            }
            $out[] = array("id"=>$i, "status"=>$status);
        }
        $this->_helper->json->sendJson($out);
    }

    public function setSourceConnectionUrlAction()
    {
        SessionHelper::reopenSessionForWriting();

        $request = $this->getRequest();
        $type = $request->getParam("type", null);
        $url = urldecode($request->getParam("url", null));
        $override = $request->getParam("override", false);

        if ($type == 'masterdj') {
            Application_Model_Preference::SetMasterDJSourceConnectionURL($url);
            Application_Model_Preference::SetMasterDjConnectionUrlOverride($override);
        } elseif ($type == 'livedj') {
            Application_Model_Preference::SetLiveDJSourceConnectionURL($url);
            Application_Model_Preference::SetLiveDjConnectionUrlOverride($override);
        }

        $this->_helper->json->sendJson(null);
    }

    public function getAdminPasswordStatusAction()
    {
        SessionHelper::reopenSessionForWriting();

        $out = array();
        $num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
        for ($i=1; $i<=$num_of_stream; $i++) {
            if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') {
                $out["s".$i] = false;
            } else {
                $out["s".$i] = true;
            }
        }
        $this->_helper->json->sendJson($out);
    }

    public function deleteAllFilesAction()
    {
        $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);

        if (!SecurityHelper::verifyCSRFToken($this->_getParam('csrf_token'))) {
            Logging::error(__FILE__ . ': Invalid CSRF token');
            $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "valid" => false, "error" => "CSRF token did not match."));
            return;
        }

        // Only admin users should get here through ACL permissioning
        // Only allow POST requests
        $method = $_SERVER['REQUEST_METHOD'];
        if (!($method == 'POST')) {
            $this->getResponse()
                 ->setHttpResponseCode(405)
                 ->appendBody(_("Request method not accepted") . ": $method");
            return;
        }

        $this->deleteFutureScheduleItems();
        $this->deleteCloudFiles();
        $this->deleteStoredFiles();

        $this->getResponse()
             ->setHttpResponseCode(200)
             ->appendBody("OK");
    }

    private function deleteFutureScheduleItems() {
        $utcTimezone = new DateTimeZone("UTC");
        $nowDateTime = new DateTime("now", $utcTimezone);
        $scheduleItems = CcScheduleQuery::create()
            ->filterByDbEnds($nowDateTime->format(DEFAULT_TIMESTAMP_FORMAT), Criteria::GREATER_THAN)
            ->find();

        // Delete all the schedule items
        foreach ($scheduleItems as $i) {
            // If this is the currently playing track, cancel the current show
            if ($i->isCurrentItem()) {
                $instanceId = $i->getDbInstanceId();
                $instance = CcShowInstancesQuery::create()->findPk($instanceId);
                $showId = $instance->getDbShowId();

                // From ScheduleController
                $scheduler = new Application_Model_Scheduler();
                $scheduler->cancelShow($showId);
                Application_Model_StoredFile::updatePastFilesIsScheduled();
            }

            $i->delete();
        }
    }

    private function deleteCloudFiles() {
        try {
            $CC_CONFIG = Config::getConfig();

            foreach ($CC_CONFIG["supportedStorageBackends"] as $storageBackend) {
                $proxyStorageBackend = new ProxyStorageBackend($storageBackend);
                $proxyStorageBackend->deleteAllCloudFileObjects();
            }
        } catch(Exception $e) {
            Logging::info($e->getMessage());
        }
    }

    private function deleteStoredFiles() {
        // Delete all files from the database
        $files = CcFilesQuery::create()->find();
        foreach ($files as $file) {
            $storedFile = new Application_Model_StoredFile($file, null);
            // Delete the files quietly to avoid getting Sentry errors for
            // every S3 file we delete.
            $storedFile->delete(true);
        }
    }

}
