/*
 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*global $, tizen, App, clearTimeout, console, setTimeout */

(function strict() {
    'use strict';

    /**
     * Constructs NFCControl object.
     * @param {App} app
     */
    App.NFCControl = function NFCControl(app) {
        this.app = app;
        this.init();
    };

    App.NFCControl.prototype = {
        nfcTarget: null,
        nfcStateMemory: false,

        /**
         * Checks if device NFC capability is present.
         */
        checkNfcCapabilities: function nfc_checkNfcCapabilities() {
            var isNfcSupported,
                self = this;

            try {
                isNfcSupported = tizen.systeminfo.getCapabilities().nfc;
            } catch (err) {
                console.error('nfc_checkNfcCapabilities: ', err.message);
                isNfcSupported = false;
            }
            if (!isNfcSupported) {
                setTimeout(function notSupportedWarning() {
                    self.app.ui.showPopupWarning('NFC is not supported on ' +
                        'your device. Application will be closed.');
                }, 500);
            }
        },

        /**
         * Returns if default nfc adapter is powered.
         * @returns {Boolean}
         */
        isNfcPowered: function nfc_isNfcPowered() {
            var isPowered = false;
            try {
                isPowered = tizen.nfc.getDefaultAdapter().powered;
            } catch (err) {
                console.error('nfc_isNfcPowered: ', err.message);
            }
            return isPowered;
        },

        /**
         * Initializes NFC object.
         */
        init: function nfc_init() {
            this.checkNfcCapabilities();
            this.card = new App.NFCCard(this);
            this.peer = new App.NFCPeer(this);
            this.endOfText = String.fromCharCode(3);
        },


        /**
         * Disables tag/target detection and moves to start page.
         * @param {string} monit Message text to be displayed.
         */
        timeExpired: function nfc_timeExpired(monit) {
            clearTimeout(this.app.timeOutHandler);

            if (this.isNfcPowered()) {
                this.unsetTargetDetect();
                this.unsetTagDetect();
            }
            this.app.ui.moveToStartPage(monit);
        },

        /**
         * Returns end of text marker.
         *
         * @return {string}
         */
        getEndOfText: function nfc_getEndOfText() {
            return this.endOfText;
        },

        /**
         * Returns contact in vCard format.
         * @param {object} contact
         * @return {string}
         */
        prepareForNFC: function nfc_prepareForNFC(contact) {
            return contact.vCard;
        },

        /**
         * Returns string which is a concatenation
         * of given value parameter and ellipsis string.
         * @param {string} value
         * @param {string} endOfText
         * @return {string}
         */
        resolveData: function nfc_resolveData(value, endOfText) {
            if (!value) {
                return '';
            }
            endOfText = endOfText || this.getEndOfText();
            return value.replace(endOfText, '…');
        },

        /**
         * Returns object with contact data.
         * @param {string} contactsString
         * @returns {object}
         */
        resolveContact: function nfc_resolveContact(contactsString) {
            var receivedContact = new tizen.Contact(contactsString, 'VCARD_30');

            return {
                phone: receivedContact.phoneNumbers[0].number,
                phone_type: receivedContact.phoneNumbers[0].types[0],
                first: receivedContact.name.firstName,
                middle: receivedContact.name.middleName,
                last: receivedContact.name.lastName,
                vCard: receivedContact.convertToString('VCARD_30')
            };
        },

        /**
         * Reads data from the object given as parameter
         * and calls displayConntact function.
         * @param {NDEFRecord} record
         */
        fillRecordInfo: function nfc_fillRecordInfo(record) {
            try {
                var contactsData = this.resolveContact(
                    this.convertNDEF2phoneNumber(record.payload)
                );
                this.app.nfc.displayContact(contactsData);
            } catch (err) {
                console.error('nfc_fillRecordInfo: ', err.message);
            }
        },

        /**
         * Performs actions related to proper reading of the received message.
         * @param {NDEFMessage} message
         */
        readMessage: function nfc_readMessage(message) {
            try {
                this.fillRecordInfo(message.records[0]);
            } catch (err) {
                console.error('nfc_readMessage: ', err.message);
            }
        },

        /**
         * Returns NDEFMessage object filled in with data from
         * contact parameter given as an argument.
         * @param {string|object} contact
         * @return {NDEFMessage}
         */
        contact2NDEF: function nfc_contact2NDEF(contact) {
            var t, a = [],
                len, i, newMessage = new tizen.NDEFMessage();
            if (typeof contact === 'string') {
                t = contact;
            } else {
                t = contact.convertToString('VCARD_30');
            }
            len = t.length;
            for (i = 0; i < len; i += 1) {
                a[i] = t.charCodeAt(i);
            }
            newMessage.records[0] =
                new tizen.NDEFRecordMedia('text/x-vcard', a);
            return newMessage;
        },

        /**
         * Returns NDEFMessage object filled in with data from
         * contact parameter given as an argument.
         * @param {string} contact
         * @return {NDEFMessage}
         */
        phoneNumber2NDEF: function nfc_phoneNumber2NDEF(contact) {
            var phoneNumberArray = [],
                i,
                length = contact.length,
                newMessage = new tizen.NDEFMessage();
            for (i = 0; i < length; i += 1) {
                phoneNumberArray.push(contact.charCodeAt(i));
            }
            newMessage.records[0] =
                new tizen.NDEFRecordMedia('text/x-vcard', phoneNumberArray);
            return newMessage;
        },

        /**
         * Returns phone number string obtained from contact parameter
         * given as an argument.
         * @param {string} contact
         * @return {string}
         */
        convertNDEF2phoneNumber: function nfc_convertNDEF2phoneNumber(contact) {
            var i, length = contact.length,
                phoneNumber = '';
            for (i = 0; i < length; i += 1) {
                phoneNumber += String.fromCharCode(contact[i]);
            }
            return phoneNumber;
        },

        /**
         * Performs action when the power of NFC adapter is on.
         */
        onPowerOn: function nfc_onPowerOn() {
            console.log('Power On succeeded.');
            this.app.started = true;
            this.app.ui.loadStartPage();
        },

        /**
         * Performs action when the power of NFC adapter
         * could not be turned on.
         * @param {Error} err
         */
        onPowerOnFails: function nfc_onPowerOnFails(err) {
            console.error('nfc_onPowerOnFails: ', err.message);
            this.app.ui.showPopupWarning();
        },

        /**
         * Performs action when the power of NFC adapter is off.
         */
        onPowerOff: function nfc_onPowerOff() {
            try {
                tizen.application.getCurrentApplication().exit();
            } catch (err) {
                console.error('nfc_onPowerOff: ', err.message);
            }
        },

        /**
         * Performs action when the power of NFC adapter
         * could not be turned off.
         * @param {Error} err
         */
        onPowerOffFails: function nfc_onPowerOffFails(err) {
            console.error('nfc_onPowerOffFails: ', err.message);
            try {
                tizen.application.getCurrentApplication().exit();
            } catch (e) {
                console.error('nfc_onPowerOffFails: ', e.message);
            }
        },

        /**
         * Return true when the power of NFC adapter is turned on,
         * false otherwise.
         * @return {boolean}
         */
        isPowered: function nfc_isPowered() {
            return this.nfcAdapter.powered;
        },

        /**
         * Performs action associated with turning on the power of NFC adapter.
         */
        startNFC: function nfc_startNFC() {
            try {
                this.nfcAdapter = tizen.nfc.getDefaultAdapter();
                if (this.nfcAdapter.powered) {
                    this.nfcStateMemory = true;
                    this.onPowerOn();
                    return;
                }
                this.nfcStateMemory = false;
                console.log('Turning NFC adapter On...');
                this.nfcAdapter.setPowered(
                    true,
                    this.onPowerOn.bind(this),
                    this.onPowerOnFails.bind(this)
                );
            } catch (err) {
                console.error('nfc_startNFC: ', err.message);
                this.app.ui.showPopupWarning();
            }
        },

        /**
         * Performs action associated with turning off the power of NFC adapter.
         */
        stopNFC: function nfc_stopNFC() {
            try {
                if (this.nfcStateMemory) {
                    this.onPowerOff();
                } else {
                    this.nfcAdapter.setPowered(
                        false,
                        this.onPowerOff.bind(this),
                        this.onPowerOffFails.bind(this)
                    );
                }
            } catch (err) {
                console.error('nfc_stopNFC: ', err.message);
            }
        },

        /**
         * Removes listeners which are necessary to proper detection
         * of another NFC devices.
         */
        unsetTargetDetect: function nfc_unsetTargetDetect() {
            try {
                if (this.nfcTarget) {
                    this.nfcTarget.unsetReceiveNDEFListener();
                    this.nfcTarget = null;
                } else {
                    console.log('app.nfc.nfcTarget is not set');
                }
            } catch (err) {
                console.error('nfc_unsetTargetDetect: ', err.message);
            }
            try {
                this.nfcAdapter.unsetPeerListener();
            } catch (err) {
                console.error('nfc_unsetTargetDetect: ', err.message);
            }
        },

        /**
         * Removes listener which is necessary to proper detection
         * of NFC tags.
         */
        unsetTagDetect: function nfc_unsetTagDetect() {
            try {
                this.nfcAdapter.unsetTagListener();
            } catch (err) {
                console.error('nfc_unsetTargetDetect: ', err.message);
            }
        },

        /**
         * Displays contact details on contact page.
         * @param {object} obj
         */
        displayContact: function nfc_displayContact(obj) {
            clearTimeout(this.app.timeOutHandler);
            if (this.isNfcPowered()) {
                this.unsetTargetDetect();
                this.unsetTagDetect();
            }
            this.app.ui.moveToContactPage(obj);
        },

        /**
         * Performs action on tag or target detach.
         */
        sucDetach: function nfc_sucDetach() {
            return;
        }
    };

}());
