<?php

require_once dirname(__FILE__) . '/../../lib/phoneprovisioning.php';
require_once dirname(__FILE__) . '/../tiptel-2xx/Tiptel.php';
require_once "TimezoneHelper.php";

class TiptelPhoneProvisioning extends VirtualPhoneProvisioningController
{

    const LOG_TAG = 'tiptel31xx-dls';

    protected function checkMacAddress($mac)
    {
        return parent::checkMacAddress($mac);
    }

    protected function getXMLURL($app)
    {
        $url = parent::getProvURL();
        return $url . $app . "/" . $this->mMacAddress . ".xml";
    }

    protected function getPhonebookURL()
    {
        return $this->getXMLURL('pb');
    }

    protected function getLoginAppURL()
    {
        return $this->getXMLURL('login');
    }

    protected function getConfigAppURL()
    {
        return $this->getXMLURL('cfgapp');
    }

    protected function getVoicemailAppURL()
    {
        return $this->getXMLURL('voicemail');
    }

    protected function checkUserAgent($ua)
    {
        //Tiptel t31xx Serie...
        $ua = str_replace(" ", " ", $ua);
        $ua_parts = explode(' ', $ua);
        if (strToLower(@$ua_parts[0]) === 'tiptel') {
            $found = false;
            $phoneType = substr(strToLower(@$ua_parts[1]), 0, 3);

            if ($phoneType === 't31') {
                $ua_model = strToLower(@$ua_parts[1]);

                foreach ($this->_getSupportedPhoneModels() as $model) {
                    if ($model->getUserAgent() == $ua_model) {
                        $this->setCurrentPhoneModel($model);
                        $found = true;
                        break;
                    }
                }
            }

            # find out the firmware version of the phone
            $fw_vers = (preg_match('/(\d+\.\d+\.\d+)/', @$ua_parts[2], $m)) ? $m[1] : '0.0.0';
            $fw_vers_nrml = $this->tiptel_normalize_version($fw_vers);
            $this->setCurrentFirmwareVersion($fw_vers_nrml);
            return $found;
        }
        return parent::checkUserAgent($ua);
    }

    protected function runFirmwareUpdate(Firmware $fwUpdate)
    {
        $this->psetting('_AutoUpload|Firmware', "http://" . cfg('PROV_HOST') . ":" . cfg('PROV_PORT') . "/firmware/" . $fwUpdate->fileName);
        return false;
    }

    protected function loadConfigValues($mac = null)
    {
        $template = $this->getTemplate();
        $Phone = $this->getPhoneModel();

        $SipAccount = $Phone->getSipAccount();

        $User = $SipAccount->getUser();
        $callwaiting = false;
        $callwaitingSound = false;
        $buttonsound = false;

        if ($User && $User->call_waiting) {
            $callwaiting = true;
            $callwaitingSound = true;
        }

        if (isset($User->key_tone) && !empty($User->key_tone)) {
            $buttonsound = true;
        }

        foreach ($template as $configfile => $values) {

            //generate psetting
            foreach ($values as $key => $value) {
                $this->psetting($configfile . '|' . $key, $value);
            }
        }

        $label = str_replace('<', '[', $SipAccount->getLabel());
        $label = str_replace('>', ']', $label);
        $displayName = str_replace('<', '[', $SipAccount->getDisplayName());
        $displayName = str_replace('>', ']', $displayName);

        $this->psetting('SIP/sipAccount0/account|SIPServerHost', $SipAccount->getSIPRegistrar());
        $this->psetting('SIP/sipAccount0/account|SIPServerPort', cfg("INTERNAL_SIP_PORT"));
        $this->psetting('SIP/sipAccount0/account|Enable', '1');
        $this->psetting('SIP/sipAccount0/account|UserName', $SipAccount->authname);
        $this->psetting('SIP/sipAccount0/account|AuthName', $SipAccount->authname);
        $this->psetting('SIP/sipAccount0/account|password', $SipAccount->secret);

        if ($User) {
            if ($User->defaultCallForwardSet != $User->callForwardSet) {
                $preset = ForwardPreset::model()->findByPk($User->callForwardSet);
                if ($preset != NULL) {
                    $label = "[" . $SipAccount->authname . "] " . $preset->name;
                    $label = str_replace('<', '[', $label);
                    $label = str_replace('>', ']', $label);
                } else {
                    $label = "FWD?";
                }
            }
        }

        $this->psetting('SIP/sipAccount0/account|Label', $label);
        $this->psetting('SIP/sipAccount0/account|DisplayName', $displayName);
        $this->psetting('system/AutoProvision|strServerURL', $this->getProvURL($mac));

        $this->psetting('SIP/sipAccount0/account|Expire', $SipAccount->expires);
        $this->psetting('SIP/sipAccount0/account|SubscribeMWIExpire', $SipAccount->expires);
        $this->psetting('SIP/sipAccount0/account|SessionExpires', $SipAccount->expires);

        $srtp = "0";
        if (cfg("RTP_ENABLE_SRTP") == "1") {
            $srtp = "1";
        }

        $this->psetting('SIP/sipAccount0/account|srtp_security', $srtp);

        // $this->psetting('_AutoAction|Reboot', 'IfRequired'); // defined in Template!
        $this->psetting('user/init|DefUserAccount', '1');
        $this->psetting('user/DND|On_Code', cfg('DP_DND_ON_PREFIX'));
        $this->psetting('user/DND|Off_Code', '*43*');

        $this->psetting('user/Features|Call_Waiting', ($callwaiting ? '1' : '0'));
        $this->psetting('user/Features|Call_WaitingTone', ($callwaitingSound ? '1' : '0'));
        $this->psetting('user/Features|ButtonSoundOn', ($buttonsound ? '1' : '0'));
        $this->psetting('SIP/sipAccount0/account|CLIR', '0');

        $this->psetting('phonekeys/SystemKeys|key_dir', 'ldap;*;');
        $this->psetting('contacts/LDAP|DisplayName', '%cn');
        $this->psetting('contacts/LDAP|MaxHits', '250');
        $this->psetting('contacts/LDAP|NameAttr', 'givenName, sn o');
        $this->psetting('contacts/LDAP|SearchDelay', '100');
        $this->psetting('contacts/LDAP|base', 'o=Persoenlich,ou=addressbooks,dc=default');
        $this->psetting('contacts/LDAP|host', $SipAccount->getSIPRegistrar());
        $this->psetting('contacts/LDAP|port', '12389');
        $this->psetting('contacts/LDAP|pswd', '439rz9f4uifh8vsfdpugh4');
        if ($User) {
            $this->psetting('contacts/LDAP|user', 'cn=' . $User->name . ',dc=default');
        }

        $tz = cfg("TIMEZONE");
        if ($User && $User->user_timezone != "") {
            $tz = $User->user_timezone;
        }

        $tz_offset = get_timezone_offset("UTC", $tz, true);
        if ($tz_offset > 0) {
            $tz_offset = "+" . $tz_offset;
        } else if ($tz_offset < 0) {
            $tz_offset = "" . $tz_offset;
        }

        Log::d("Timezone offset: " . $tz_offset . " (" . cfg("TIMEZONE") . ")", self::LOG_TAG);
        $this->psetting('system/LocalTime|TimeZone', $tz_offset); # -11 to +23
        $this->psetting('system/LocalTime|TimeServer1', cfg("NTP_HOST")); # NTP Server 1

        $time_format = cfg("USER_TIME_FORMAT");
        if ($User && $User->user_time_format != "") {
            $time_format = $User->user_time_format;
        }

        if ($time_format == "24") {
            $this->psetting('system/LocalTime|TimeFormat', "1");
        } else {
            $this->psetting('system/LocalTime|TimeFormat', "0");
        }

        $language = $this->getLanguage($User);
        $languageFormat = $this->getPhoneUseableLanguageFormat($User);

        $this->psetting('user/Lang|Language', $languageFormat);
        $this->psetting('user/Lang|ActiveWebLanguage', $languageFormat);

        if ($User) {
            $this->psetting('phonekeys/SystemKeys|key_dir', 'uri;;' . $this->getPhonebookURL() . ";0");
            $this->psetting('phonekeys/SystemKeys|key_rkey', 'uri;;' . $this->getConfigAppURL() . ";0");
            $this->psetting('phonekeys/SystemKeys|key_cursor_right', 'uri;' . $this->getXmlVoicemailKeyName($language) . ';' . $this->getVoicemailAppURL() . ";0");
        } else {
            $this->psetting('phonekeys/SystemKeys|key_dir', 'default');
            $this->psetting('phonekeys/SystemKeys|key_rkey', 'default');
            $this->psetting('phonekeys/SystemKeys|key_cursor_right', 'uri;Login;' . $this->getLoginAppURL() . ";0");
        }

        $this->setRingtoneSettings();
        $this->setVolumeSettings($User);
        $this->setAudioCodecs();
        $this->processSoftkeys();

        $this->changeSettingsWithProvisioningProfile($User, $Phone->type);
        return true;
    }

    protected function getLanguage($User)
    {
        $language_format = cfg("GUI_LANGS");
        if ($User && $User->user_language != "") {
            $language_format = $User->user_language;
        }
        return $language_format;
    }

    protected function getPhoneUseableLanguageFormat($User)
    {
        $language = $this->getLanguage($User);
        $language_format = 'en';

        $language = substr($language, 0, strpos($language, '_'));

        if (!empty($language)) {
            $language_format = $language;
        }
        return $language_format;
    }

    protected function getExtTiptelModules()
    {
        $ext = array();
        $Phone = $this->getPhoneModel();
        $getSupportedPhoneModels = Tiptel::getSupportedPhoneModels();
        $extModules = $getSupportedPhoneModels[$Phone->type]->getExtModules();
        if ($extModules != 0) {
            for ($i = 0; $i <= $extModules - 1; $i++) {
                $ext[] = "ext" . $i;
            }
        }
        return $ext;
    }

    protected function processSoftkeys()
    {
        $Phone = $this->getPhoneModel();
        $SipAccount = $Phone->getSipAccount();
        $User = $SipAccount->getUser();
        $ext = $this->getExtTiptelModules();

        $levels = array("line", "memory");

        if (!empty($ext)) {
            $levels = array_merge($levels, $ext);
        }

        foreach ($levels as $level) {

            $softKeys = $Phone->getCurrentPhoneKeys($User, $level);
            foreach ($softKeys as $softKey) {
                $this->processSoftKey($softKey);
            }
        }
    }

    protected function processSoftKey(PhoneKey $key)
    {
        if ($key->function === 'no') {
            return;
        }
        if ($key->function === '') {
            $key->function = '0';
        }
        $keyFunction = $this->convertSoftKeyFunction($key->function, 'blf');
        $key->function = $this->setKeyFunctionForOldKeys($key->function);
        $keyValue = $this->getConvertedSoftKeyValue($key->function, $this->convertSoftKeyValue($key));
        $keyNumber = $this->convertKeyNumber($key, $keyValue);
        $keyLabel = $key->label;
        $keyIndex = $key->key_idx;
        $extModules = $this->getExtTiptelModules();
        $parameter = 'phonekeys/FunctionKeys|fkey';

        if ($key->level === 'line') {
            $parameter = 'phonekeys/SelectionKeys|fkey';
        } else if (startsWith($key->level, 'ext')) {
            foreach ($extModules as $extModule) {
                $ext = explode('.', $key->key_idx);
                if ($ext[0] == $extModule) {
                    $extNumber = explode('ext', $extModule);
                    $parameter = 'phonekeys/ExtKeys' . $extNumber[1] . '/FunctionKeys|fkey';
                    $keyIndex = $ext[1];
                }
            }
        }
        return $this->setSoftKeySettings($parameter . $keyIndex, $keyFunction, $keyLabel, $keyNumber, $keyValue);
    }

    protected function convertSoftKeyFunction($keyFunction, $blfKey)
    {
        if (startsWith($keyFunction, 'X')) {
            $keyFunction = $blfKey;
        } else {
            $keyMap = $this->getTiptelKeyMap();
            if (isset($keyMap[$keyFunction])) {
                $keyFunction = $keyMap[$keyFunction];
            }
        }
        return $keyFunction;
    }

    protected function getTiptelKeyMap()
    {
        return array(
            '0' => 'override', // Override Key
            '6' => 'callreturn', // Redial
            '13' => 'dial', // Speed Dial
            '15' => 'line', // Line (for line key only)
            '16' => 'blf', // BLF	
            '25' => 'record_call', // Record
        );
    }

    protected function setKeyFunctionForOldKeys($keyFunction)
    {
        if ($keyFunction == 'blf' || $keyFunction == 16) {
            $keyFunction = 'X06';
        }
        return $keyFunction;
    }

    protected function getConvertedSoftKeyValue($keyFunction, $keyValue)
    {
        if ($keyFunction == 'X06') {
            $keyValue = cfg('DP_PICKUP_PREFIX') . $keyValue;
        }
        return $keyValue;
    }

    protected function convertKeyNumber($key, $keyValue)
    {
        $keyNumber = $key->number_data;
        if (($keyNumber == '' && $keyValue != '') || (startsWith($key->function, 'X') && $key->function != 'X06')) {
            $keyNumber = $keyValue;
        }
        return $keyNumber;
    }

    protected function setSoftKeySettings($parameter, $function, $label, $number, $numberPrefix)
    {
        if (!empty($function)) {
            if ($function === 'override') {
                $function = '';
            }
            return $this->psetting($parameter, $function . ';' . $label . ';' . $number . ';1;' . $numberPrefix);
        }
        return '';
    }

    protected function generateOutput()
    {
        foreach ($this->mCurrentSettings as $section_name => $section_values) {
            Log::d('[ ' . $section_name . ' ]', self::LOG_TAG);
            echo '[ ', $section_name, ' ]', "\n";
            foreach ($section_values as $name => $val) {
                Log::d($name . ' = ' . $val, self::LOG_TAG);
                echo $name . ' = ' . $val, "\n";
            }
            echo "\n";
        }
        return false;
    }

    protected function _getSupportedPhoneModels()
    {
        return Tiptel::getSupportedPhoneModels();
    }

    private function tiptel_normalize_version($fwvers)
    {
        $tmp = explode('.', $fwvers);
        $v0 = str_pad((int) @$tmp[0], 2, '0', STR_PAD_LEFT);
        $v1 = str_pad((int) @$tmp[1], 2, '0', STR_PAD_LEFT);
        $v2 = str_pad((int) @$tmp[2], 2, '0', STR_PAD_LEFT);
        return $v0 . '.' . $v1 . '.' . $v2;
    }

    private function getTemplate()
    {
        $contents = file_get_contents(dirname(__FILE__) . "/templates/" . $this->mCurrentPhoneModel->getPhoneModelName() . ".tpl");

        $contents = explode("\n", $contents);
        $config = array();
        $currentsection = "";
        foreach ($contents as $line) {

            $line = trim($line);

            if (strlen($line) == 0) {
                continue;
            }

            if ($line[0] == "#") {
                continue;
            }

            if ($line[0] == ";") {
                continue;
            }

            if ($line[0] == "[") {
                $currentsection = $line;
                $currentsection = trim($currentsection, "][ ");
                continue;
            }

            $parts = explode("=", $line);

            $key = trim($parts[0]);
            $value = trim(@$parts[1]);

            $config[$currentsection][$key] = $value;
        }
        return $config;
    }

    protected function psetting($sectionname, $val = '')
    {
        if (strPos($sectionname, '|')) {
            list($section, $name) = explode('|', $sectionname);
            if ($section !== '' && $name !== '') {
                if (!array_key_exists($section, $this->mCurrentSettings) || !is_array($this->mCurrentSettings[$section])) {
                    $this->mCurrentSettings[$section] = array();
                }
                $this->mCurrentSettings[$section][$name] = $val;
            }
        }
    }

    protected function getXmlVoicemailKeyName($language)
    {
        $keyName = "VMail";
        if ($language === "de_de") {
            $keyName = "AB";
        }
        return $keyName;
    }

    protected function setRingtoneSettings()
    {
        for ($i = 0; $i <= 9; $i++) {
            $ringKey = $i + 1;
            $this->psetting("user/AlertInfo$i|Text", "Ringer$ringKey");
            $this->psetting("user/AlertInfo$i|Ringer", $this->getTiptelRingtone($i));
        }
    }

    protected function getTiptelRingtone($key)
    {
        $changedRingtone = 'System: 1 Phone Bright.wav';
        $ringtoneArray = array(
            'System: 1 Phone Bright.wav',
            'System: 2 Phone Fast.wav',
            'System: 3 Phone Slow.wav',
            'System: 4 Classic Phone.wav',
            'System: 5 Beep.wav',
            'System: 6 Tiptel Sound.wav',
            'System: 7 Melody.wav',
            'System: 8 Bird.wav',
            'System: Bellcore-dr1.wav',
            'System: Bellcore-dr2.wav'
        );

        if (isset($ringtoneArray[$key])) {
            $changedRingtone = $ringtoneArray[$key];
        }
        return $changedRingtone;
    }

    protected function setAudioCodecs()
    {
        $phonalisaCodecs = str_replace(' ', '', cfg('GLOBAL_CODEC_PREFS'));
        $codecs = explode(',', $phonalisaCodecs);
        $phoneCodecs = $this->getPhoneCodecs();
        $accountCount = 8;

        foreach ($codecs as $key => $value) {
            if (array_key_exists($value, $phoneCodecs)) {
                $phoneCodecs[$value]['enable'] = 1;
                $oldPriority = $phoneCodecs[$value]['priority'];
                $oldCodecWithPriority = $this->searchForPriority($key, $phoneCodecs);
                $phoneCodecs[$oldCodecWithPriority]['priority'] = $oldPriority;
                $phoneCodecs[$value]['priority'] = $key;
            }
        }

        for ($i = 0; $i <= (int) $accountCount; $i++) {
            $this->setAudioCodecToSettings($phoneCodecs, $i);
        }
    }

    protected function getPhoneCodecs()
    {
        $codecs = array(
            'PCMA' => 8,
            'PCMU' => 0,
            'G722' => 9,
            'GSM' => 3,
            'L8' => 120,
            'L16' => 122
        );

        $result = array();
        $priority = 0;
        foreach ($codecs as $codec => $rtpmap) {
            $result[$codec] = array(
                'enable' => 0,
                'PayloadType' => $codec,
                'priority' => $priority,
                'rtpmap' => $rtpmap,
            );
            $priority++;
        }
        return $result;
    }

    protected function searchForPriority($id, $array)
    {
        foreach ($array as $key => $val) {
            if ($val['priority'] === $id) {
                return $key;
            }
        }
        return null;
    }

    protected function setAudioCodecToSettings($phoneCodecs, $account)
    {
        $priority = 0;
        foreach ($phoneCodecs as $codecKey => $codec) {
            $key = "SIP/sipAccount$account/audio$priority";
            $this->psetting("$key|enable", $codec['enable']);
            $this->psetting("$key|PayloadType", $codecKey);
            $this->psetting("$key|priority", $codec['priority']);
            $this->psetting("$key|rtpmap", $codec['rtpmap']);
            $priority++;
        }
    }

    protected function setVolumeSettings($User)
    {
        if ($User) {
            $this->setVolumeUserSettings($User);
        } else {
            $this->psetting('user/PhoneVolume|HandFreeSpkVol', 5);
            $this->psetting('user/PhoneVolume|HandSetSpkVol', 5);
            $this->psetting('user/PhoneVolume|HeadSetMicVol', 5);
            $this->psetting('user/PhoneVolume|HeadSetSpkVol', 5);
            $this->psetting('user/PhoneVolume|RingVol', 5);
        }
    }

    protected function setVolumeUserSettings($User)
    {
        $userSettings = $User->getSettings();
        if ($userSettings) {
            $settings = $userSettings->attributes;
            unset($settings['userId']);
            foreach ($settings as $key => $value) {
                if (empty($value)) {
                    return $this->setVolumeSettings(false);
                }
                $divisor = 9 / 10;
                $value = (int) $value * $divisor;
                $settings[$key] = round($value) - 1;
            }

            $this->psetting('user/PhoneVolume|HandFreeSpkVol', $settings['speakerVolume']);
            $this->psetting('user/PhoneVolume|HandSetSpkVol', $settings['headsetVolume']);
            $this->psetting('user/PhoneVolume|HeadSetMicVol', $settings['headsetMicroVolume']);
            $this->psetting('user/PhoneVolume|HeadSetSpkVol', $settings['headsetVolume']);
            $this->psetting('user/PhoneVolume|RingVol', $settings['ringVolume']);
        }
    }
}
