/**
 * 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/>.
 *
 */

var {Cc, Ci, Cu, Cm, Cr} = require("chrome");

var observerService = Cc["@mozilla.org/observer-service;1"]
    .getService(Ci.nsIObserverService);

var acceptedScripts = require("script_entries/accepted_scripts").acceptedScripts;
var allowedRef = require('http_observer/allowed_referrers').allowedReferrers;

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

var scriptAnalyzer = {

    // the URL of the current page.
    pageURL: null,

    /*
     * analyzeScriptBeforeExec
     *
     * Ensure that the script is found in the acceptedScript before
     * allowing to execute it.
     *
     */
    analyzeScriptBeforeExec: function (e) {
	//console.log('analyzeScriptBeforeExec executed');

	var script = e.target, isAccepted;
	
        this.pageURL = urlHandler.removeFragment(script.ownerDocument.URL);
	if (!allowedRef.urlInAllowedReferrers(this.pageURL)) {

	    if (script.src != undefined && 
		script.src != '') {
		
		isAccepted = this.checkExternalScript(script);
		
	    } else {

		isAccepted = this.checkInlineScript(script);

	    }

	    if (isAccepted === false && 
		!(/^(file:\/\/|chrome:\/\/|about\:)/.test(this.pageURL))) {
		//console.log(this.pageURL);
		// file:// types of pages are allowed.

		// set invalid type so that the script is detected
		// by LibreJS as blocked (although it's blocked using
		// preventDefault().
		script.setAttribute('type', 'librejs/blocked');

		console.log('prevent default triggered jsLoadObserver', script.src, script.text);
		e.preventDefault();
		return false;

	    } else {

		return true;

	    }

	} else {

	    return true;

	}

	return false;

    },

    checkExternalScript: function (script) {
	var url = urlHandler.resolve(this.pageURL, script.src);


	if  (this.isScriptAccepted(url, false)) {
	   
	    // url in src attribute is found as accepted.
	     return true;

	 }
	
	else {
	    // the script hasn't been accepted before.
	    // block it.
	    return false;
	}

    },

    checkInlineScript: function (script) {
	return this.isScriptAccepted(script.text, true);
    },

    isScriptAccepted: function (contents, inline) {
	
	if (!acceptedScripts.isFound(this.pageURL, {'inline': inline, 'contents': contents})) {
	    return false;
	} 

	else {
	    return true;
	}

    }

};

exports.scriptAnalyzer = scriptAnalyzer;


var jsLoadObserver = {

    observe: function (domWindow) {

	domWindow.document.addEventListener("beforescriptexecute", scriptAnalyzer.analyzeScriptBeforeExec.bind(scriptAnalyzer), false);

    }
};

observerService.addObserver(jsLoadObserver, 
			    'content-document-global-created',
			    false);



exports.removeJsLoadObserver = function () {
    observerService.removeObserver(jsLoadObserver,
				   'content-document-global-created');
    console.log('removing jsLoadObserver');
};