/**
 * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
 * *
 * Copyright (C) 2011, 2012 Loic J. Duros
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see  <http://www.gnu.org/licenses/>.
 *
 */



// page mod executing content script at every page load.

var data = require("self").data;
var pageMod = require("page-mod");

var urlHandler = require("url_handler/url_handler");

var pageWorker = require("page-worker");

var scriptList = require("ui/script_list");


var panelRemovedScripts = scriptList.rejectedScriptsList;
var panelAcceptedScripts = scriptList.acceptedScriptsList; 

// contain list of recently found contact links or email addresses.
var contactList = {};

// constants. Also available in lib/ui_info.js
const CERTAIN_EMAIL_ADDRESS_FOUND = 'certainEmailAddressFound';
const UNCERTAIN_EMAIL_ADDRESS_FOUND = 'uncertainEmailAddresFound';

// Looking for contact links
const CERTAIN_LINK_FOUND = 'certainLinkFound';
const PROBABLE_LINK_FOUND = 'probableLinkFound';
const UNCERTAIN_LINK_FOUND = 'uncertainLinkFound';
const LINK_NOT_FOUND = 'contactLinkNotFound';

// Looking for identi.ca and twitter accounts.
const TWITTER_LINK_FOUND = 'twitterLinkFound';
const IDENTICA_LINK_FOUND = 'identicaLinkFound';

// phone number and address
const PHONE_NUMBER_FOUND = 'phoneNumberFound';
const SNAIL_ADDRESS_FOUND = 'snailAddressFound';



/**
 * main pageMod.
 * Find blocked script in all pages being opened.
 * Launch the scripts that search for a complaint contact.
 * 
 */

pageMod.PageMod({
		    
		    include: ['file://*','*', 'data:*', 'about:*'],

		    contentScriptWhen: 'end',

		    contentScriptFile: [
			data.url('complain/contact_regex.js'),
			data.url('complain/link_types.js'),
			data.url('third_party/jquery-src.js'), 
			data.url('third_party/jquery.easing.1.3.js'),
			data.url('complain/contact_finder.js'),
			data.url('complain/pagemod_finder.js'),
			data.url('script_detector/script_detector.js')
		    ],

		    onAttach: function onAttach(worker) {
			
			if (worker.tab != undefined) {
			    
			    // this is a tab.
			    if (!foundInContactList(worker.url)) {
				// the hostname doesn't appear in the object literal.
				// run script fetching/complaint feature if applicable.
				tabProcess(worker);
			    } else {
				worker.postMessage(foundInContactList(worker.url));
			    }
			} 

		    }
		});

/**
 * foundInContactList
 *
 * Provides link if contact link is found for given url, or else
 * false.
 */
var foundInContactList = function (url) {

    var hostname = urlHandler.getHostname(url);
    
    if (contactList[hostname] != undefined) {

	return contactList[hostname];

    } else {

	return false;

    }

};


/**
 * addScriptsToPanelList
 *
 * Looks for scripts that are either valid or flagged with libreJS
 * 
 */ 
var addScriptsToPanelList = function (worker, respData) {

    // use url. remove fragment.
    var url = urlHandler.removeFragment(worker.tab.url);
    var contents, i;

    // set script lists as empty arrays if 
    // they don't exist
    setScriptArrays(url);

    for (i = 0; i < respData.value.blocked.length; i++) {

	// if external script only.
	pathToUrl(respData.value.blocked[i], url);

	panelRemovedScripts[url].push(respData.value.blocked[i]);

    }
    


    for (i = 0; i < respData.value.accepted.length; i++) {

	// if external script only.
	pathToUrl(respData.value.accepted[i], url);

	panelAcceptedScripts[url].push(respData.value.accepted[i]);

    }

};

var setScriptArrays = function (index) {
    if (panelRemovedScripts[index] == null) {
	panelRemovedScripts[index] = [];
    }
    if (panelAcceptedScripts[index] == null) {
	panelAcceptedScripts[index] = [];
    }  
};

/**
 * clearScriptsFromClosedTab
 * 
 * Whenever a tab is closed, clear the script
 * arrays corresponding to it.
 * 
 */
exports.clearScriptsFromClosedTab = function () {

    var tabs = require("tabs");

    // use url as property. remove fragment.


    var resetScripts = function (tab) {
	var url = urlHandler.removeFragment(tab.url);
	panelRemovedScripts[url] = [];
	panelAcceptedScripts[url] = [];
    };


    tabs.on('ready', function (tab) {
		resetScripts(tab);
	    });
    
};

/**
 * pathToUrl
 * 
 * convert a relative path to a url.
 * 
 */
var pathToUrl = function (scriptEntry, url) {
    if (scriptEntry.inline === false) {
	scriptEntry.url = urlHandler.resolve(url, scriptEntry.url);
    }
};

/**
 * tabProcess
 * Find blocked/accepted scripts, prepare
 * display panel and complaint panel, ...
 * 
 */
var tabProcess = function (worker) {

    var visitedUrl = {};

    // webmaster email is better than a webpage.
    worker.emailFound = false;
    var modUrl = '',
    searchUrl = '';

    modUrl = worker.url;

    //console.log('pagemod triggered');

    worker.postMessage({'event': 'tabProcess'});

    // send local path to complain button graphic.
    worker.postMessage({'event': 'assets-uri', 'value':  data.url('assets/')});
    worker.postMessage({'event': 'page-url', 'value': modUrl});

    worker.on('message', function (respData) {
        
	// console.log('worker is receiving a message', respData.event);

	var pw;

	worker.on('detach', function () {
	    //console.log('detaching worker');
	    if (pw) {

		pw.destroy();

	    }
	});

	// display list of blocked/allowed scripts.
	if (respData.event === 'scriptsFetched') {
	    // add scripts to list.
	    //console.log('script fetched for', modUrl);
	    addScriptsToPanelList(worker, respData);
	}


	else if (respData.contact != undefined) {
	    // pass the message to the complaint display panel.
	    worker.postMessage(respData);	
	}
	
	else if (respData.event === 'complaintSearch') {

	    //console.log('complaintSearch triggered');

	    

	    //console.log('worker tab url', worker.tab.url);
	    if (!(respData.urlSearch.linkValue in visitedUrl)) {

		visitedUrl[respData.urlSearch.linkValue] = 1;

		respData.urlSearch.linkValue = urlHandler.addFragment(respData.urlSearch.linkValue, 'librejs=true');
		pw = searchSecondLevelPage(this, respData.urlSearch.linkValue, this.url);

	    } 
	    // currently not needed.
	    /*else {
		console.log(respData.urlSearch.linkValue, 'already visited');
	    }*/
	}
	

    });

};

var searchSecondLevelPage = function (worker, urlToSearch, originalUrl) {
    var originalWorker = worker;

    //console.log('url to search is', urlToSearch);

    //console.log(urlToSearch, 'and', originalUrl);
    
   if (urlHandler.haveSameHostname(urlToSearch, originalUrl)) {

	return pageWorker.Page({
	    contentURL: urlToSearch,
	    contentScriptFile: [
		data.url('complain/contact_regex.js'),
		data.url('complain/link_types.js'),
		data.url('third_party/jquery-src.js'), 
		data.url('third_party/jquery.easing.1.3.js'),
		data.url('complain/contact_finder.js'),
		data.url('complain/worker_finder.js')
	    ],
	    contentScriptWhen: "end",
	    
	    onMessage: function (respData) {
		originalWorker.postMessage(respData);		
		if (respData.event === 'destroy') {
		    try {
			//console.log('destroying worker', this.contentURL);
			this.destroy();
		    } catch (e) {
			console.log('in worker', e);
		    }
		}
	    }
	});

   }

};




exports.testModule = {

    'contactList': contactList,

    'foundInContactList': foundInContactList,
    
    'tabProcess': tabProcess

};