/* Copyright (c) 2006-2007 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/release-license.txt 
 * for the full text of the license. */

/** 
 * @class
 *  
 * @author Lorenzo Becchi (ominiverdi.org)
 * @projectDescription ticket #687
 * 
 * @requires OpenLayers/Control.js
 */
OpenLayers.Control.myWMSManager = OpenLayers.Class( OpenLayers.Control, {

    /*
	* At the end of the process tells if any server is available
	*/
	serverAvailable: false,
	
	errorMessage: null,
	
	serverProblem: false,
	
	isOurProjectionAccepted: false,
	
	/*
	* Points to the next entry of the aWMSServers to be tested
	*/	
    ServerIndex: null,
    
    selecterServer: null,
    serverVersion: null,
	//Arrays
    /** @type Array
    !!!!!!In preference order!!!!!    */
    aWMSServers: null,
	
	//WMS layers features
	/** @type Array
	 *  @param Name:Title:Abstract:BoundingBox:LegendURL:queryable
	 */ 
	aWMSLayers: [],
	
	//Image formats for WMS server
	/** @type Array
	 */ 
	aImageFormats: [],

	
	//WMS default params
	/** @type string */
    exceptionsValue: 'application/vnd.ogc.se_inimage',//OL default value
	resolutionsValue: null,//OL default value
	
 
    /**
    * @constructor
    */
    initialize: function() {
        OpenLayers.Control.prototype.initialize.apply(this, arguments);
		//log("it seems to have worked",1);
    },

    startSearch: function(serverList) {
        log("clearing manager",1);
        this.clearManager();
		this.aWMSServers= serverList;
		if (this.aWMSServers.length>0) {
		    this.connect2server();
		}else {
		    alert("Server List Empty");
		}		
    },
    
    clearManager: function (){
        log("log cleared automatically",0);
        this.errorMessage=null;
	    this.serverProblem=false;
        this.isOurProjectionAccepted= false;
	    this.ServerIndex= 0;
        this.selecterServer= null;
        this.serverVersion= null;
        this.aWMSLayers= [];
	},
    
    serverConnectionCheck: function() {     
        if (!this.serverProblem) {
            this.selectedServer= this.aWMSServers[this.ServerIndex];
            log("SERVICE AVAILABLE!!!",1);
            init2();
        }else{
            log("Something went wrong in entry "+ this.serverIndex +" : "+ this.errorMessage,1); 
            if (this.ServerIndex < this.aWMSServers.length-1) {
                this.ServerIndex ++;
                this.connect2server();
            }else{
                log("No more Servers in the list",1);    
            }
        }
    },
       
    connect2server: function() {
	    //log("ServerIndex: "+this.ServerIndex+ " of " + this.aWMSServers.length,1);	 
	    this.isOurProjectionAccepted=false;
	    this.errorMessage=null;
	    this.serverProblem=false;
	    
        if (this.ServerIndex < this.aWMSServers.length) {
		    //Take the next url from the server list
		    url = this.aWMSServers[this.ServerIndex];
		     
		    if(url.length>0) {
			    this.baseURL = url;
		    } else {
                this.serverProblem=true;
                this.errorMessage="url not valid";
			    //this.serverAvailable=false;
			    this.serverConnectionCheck('url not valid2');
			    //return;
		    } 
	        if (this.baseURL.indexOf('?') == -1)
	        {
	            this.baseURL = this.baseURL + '?';
	        }
	        else
	        {
	            if (this.baseURL.charAt( this.baseURL.length - 1 ) == '&'){
	                this.baseURL = this.baseURL.slice( 0, -1 );
	            }
	        }
    		
	        this.baseURL = this.baseURL+ "&service=WMS";
	        this.baseURL = this.baseURL +  "&version=1.1.1";
	        this.baseURL = this.baseURL + "&request=GetCapabilities";
    	    
	        log ("Loading Layers list from: " + this.baseURL,1);
            OpenLayers.loadURL(this.baseURL, null, this, this.handleReply, this.requestFailure);
        }    
        else {
           this.serverProblem=true;
           this.errorMessage="serverIndex is out of range\n";
           //this.serverAvailable=false;
           this.serverConnectionCheck("serverIndex is out of range2");
        }
    },

    /*
    *  Controls that the XML reply has arrived correctly
    *  !!! Called in "window" context. "manager" is used to call the parser
    *       but it is implementation dependent
    */
    handleReply: function(ajaxRequest) {
        if (ajaxRequest.readyState==4){
            if (ajaxRequest.status==200){
                log("request status OK",1);
                //log("caller: "+ this,1);
                manager.parseReply(ajaxRequest);
            }else{
                //Go to the next server
                manager.serverProblem=true;
                manager.errorMessage="request status is "+ajaxRequest.status+" "+ajaxRequest.statusText;
                //manager.serverAvailable=false;
                manager.serverConnectionCheck("request status is "+ajaxRequest.status+" "+ajaxRequest.statusText+"2");
            }
        }else{
            //this["manager"].serverAvailable=false;
            //this["manager"].serverConnectionCheck("nonsense behavior of the capabilityRequest.readyState");
            manager.serverProblem=true;
            manager.errorMessage="nonsense beavior of the capabilityRequest.readyState";
            //manager.serverAvailable=false;
            manager.serverConnectionCheck("nonsense behavior of the capabilityRequest.readyState");
        }
        
    },
    
    requestFailure: function(errorObject) {
        //manager.serverAvailable=false;
        log ("fake handling of url load error",1);
        //errorObject.readyState=0;
        //errorObject.status=0;
        //manager.serverConnectionCheck("Error loading capabilities: "/*+errorObject.responseText*/);
    },
    
    parseReply: function(ajaxRequest) {
        //log("parsing1",1);
        var text = ajaxRequest.responseText;
        
        //myregexp = new RegExp('<!--[^(-->)]*-->');
	    text = text.replace(/<!--.*?-->/g, ''); //Helped with ESA server
	    //text = text.replace(/<!--.*$/g, ''); //Helped with ESA server
	    //text = text.replace(/^.*-->/g, ''); //Helped with ESA server
	    text = text.replace(/\[.<!.*?>.\]/g, ''); //Helped with ESA server
	    text = text.replace(/<GetTileService>.*?GetTileService>/g, '');//skip NASA DTD error
		
		/*var x=0;
		var i=text.search(/\<\!--/);
		var j=text.search(/--\>/);
		log ("i: "+ i+" j: "+ j,1);
		while (i!=-1){
		    text = "".concat(text.slice(0,i),text.slice(j+3));
		    x++;
		    i=text.search(/\<\!--/);
		    j=text.search(/--\>/);
		}
		log ("x: "+x,1);
		text = text.replace(/ *$/,"XXX");
		
		parts = text.split("?>");
		//log("browser: "+navigator.appName,1);
		if (parts[0].search(/encoding=/i) == -1){
		   //log("No encoding found",1);
		   //if (navigator.appName.search(/explorer/i) != -1) {
		        log("NO VA A FUNCIONAR!!!",1);
		        parts[0]=parts[0]+" encoding=\"UTF-8\"";
		        text = parts[0].concat("?>",parts[1]);
		   //}
		}

		var text1 = text.replace(/</g,"KKK");
		var text1 = text1.replace(/>/g,"QQQ");
		var text1 = text1.replace(/[\n\r]+/g,"<br/>");
		var newDoc= window.open().document;
		newDoc.write(text1);
		//document.write(text);
		//for (i=3; i<parts.length; i++) log (" "+i+": "+parts[i],1);			
		*/	
	    var xml = OpenLayers.parseXMLString(text);
		
	    if(xml == null) {
	            this.serverProblem=true;
                this.errorMessage+="incorrect content: check your WMS url\n";
	            //this.serverAvailable=false;
                //this.serverConnectionCheck('incorrect content: check your WMS url2');
	    }else{
	        if(xml.childNodes.length==0) {
		        try{
			        if(OpenLayers.Ajax.getParseErrorText(xml) == OpenLayers.Ajax.PARSED_OK){
		              // The document was parsed/loaded just fine, go on
	                    this.serverProblem=true;
                        this.errorMessage+="no Layers available on this server\n";
	                    //this.serverAvailable=false;
                        //this.serverConnectionCheck('no Layers available on this server');
		            } 
		            else{
		      	        // The document was not loaded correctly! Inform the user:
				        var error = OpenLayers.Ajax.getParseErrorText(xml);
	                    this.serverProblem=true;
                        this.errorMessage+="error loading/parsing the XML: "+error+"\n";
	                    //this.serverAvailable=false;
                        //this.serverConnectionCheck("error loading/parsing the XML: "+error);
		            };
		        } catch(e){
	                this.serverProblem=true;
                    this.errorMessage+="Unexpected exception on 0 Nodes: " +e.description+"\n";
	                //this.serverAvailable=false;
                    this.serverConnectionCheck("Unexpected exception on 0 Nodes: " +e.description);
		        }
	        } else {
        		
	            if(typeof xml=='object'){		 	
		            //Print Layer List
		            var aLayer = xml.getElementsByTagName('Layer');
		            if(aLayer.length>0){
			            this.extractLayers(xml);
		                if (this.aWMSLayers.length>0){
		                    this.serverProblem=false;
		                    log("Number of layers available: "+this.aWMSLayers.length,1);
                            //this.serverConnectionCheck("Number of layers available: "+this.aWMSLayers.length);  			 
                        }            
                    }
                    if (aLayer.length<=0 ||  this.aWMSLayers.length<=0){
                        this.serverProblem=true;
                        this.errorMessage+="No layers available at "+ this.aWMSServers[this.ServerIndex]+"\n";
                        //this.serverAvailable=false;
                        //this.serverConnectionCheck("No layers available at "+ this.aWMSServers[this.ServerIndex]);  			 
                    }
	             } else {
	                this.serverProblem=true;
                    this.errorMessage+="connection error: response is not an object"+"\n";
                    //this.serverAvailable=false;
                    //this.serverConnectionCheck('connection error: response is not an object');
	             }
	        }
	        
	        //All options finish here to check the result
	        this.serverConnectionCheck();
	    }
    },

    extractLayers: function(xml) {
        
        //getCapabilities
		var Capability = xml.getElementsByTagName('Capability')[0];
		var layerCont = this.findChildByName(Capability,'Layer');
		
		/**
		*   Checks if the desired projection system is accepted
		*   and sets the isOurProjectionAccepted property
		**/
		var serverProj = this.findChildrenByName(layerCont,'SRS');
		//log("number of projections: " + serverProj.length,1);
		for (i=0;i<serverProj.length;i++){
		    //log ("projection "+i+": "+ OpenLayers.Ajax.getText(serverProj[i]), 1);
		    if (Projec == OpenLayers.Ajax.getText(serverProj[i])){
		        this.isOurProjectionAccepted=true;
		        break;  
		    }
		} 
		if (!this.isOurProjectionAccepted){
		    this.serverProblem=true;
            this.errorMessage+=" Projection system not accepted\n";
		    //this.serverAvailable=false;
            //this.serverConnectionCheck('Projection system not accepted');
		}else{
		
		    /**
		    * Retrieve mapping servioce version
		    *
		    **/
    		
    		
		    var aLayers = this.findChildrenByName(layerCont,'Layer');
    		
		    /***
		    * Looking for nested layers:
		    * it extends aLayers with the possible nested layers
		    */
		    var aLayersTemp = [];
		    for(i=0;i<aLayers.length;i++){
			    try{    			
			        aLayersTemp.push(aLayers[i]);
			        var n = aLayers[i];
                    //Removed piece of code without sense
                    var x  = n.firstChild;
			    } catch(e){alert(e)}
		        while (true) {
		    	    if(x.nodeType==1 && x.nodeName=='Layer'){	
					    var nameNodeN = this.findChildByName(n,'Name');
					    var titleNodeN = this.findChildByName(n,'Title');
					    //If it is only a nesting layer
					    if(!nameNodeN && titleNodeN) {aLayers.push(x);} //aLayersTemp.push(x);
					    else {aLayersTemp.push(x);}
				    } 
				    if (x == n.lastChild) break;
				    else x=x.nextSibling;		
		        }
		    }
		    aLayers = aLayersTemp;
		    /***
		    * Finished Looking for nested layers
		    */
    		
		    for(i=0;i<aLayers.length;i++){
		        try{
		            var iLayer = new Object();
		            //Layer properties
		            if (aLayers[i].getAttribute('queryable')) iLayer.Queryable=aLayers[i].getAttribute('queryable');
		            if (aLayers[i].getAttribute('opaque')) iLayer.opaque=aLayers[i].getAttribute('opaque')
		            if (aLayers[i].getAttribute('cascaded'))iLayer.cascaded=aLayers[i].getAttribute('cascaded')
    		        
    		        
		            var nameNode = this.findChildByName(aLayers[i],'Name');
		            if(nameNode)var Name =OpenLayers.Ajax.getText(nameNode);
		            else var Name = null;
		            log("i: " +i+ " name: "+Name,1);
		            iLayer.name=Name;
            		
		            var titleNode = this.findChildByName(aLayers[i],'Title');
		            if(titleNode)var Title =OpenLayers.Ajax.getText(titleNode);
		            else var Title = null;
                    //log("     title: "+Title,1);
                    iLayer.title=Title;        		
            		
        		    //To make sure we doesn't print the NoName Layers used
        		    //in the nesting
        		    if (iLayer.name && 
        		                !iLayer.name.match("AND:")){ //to avoid layers of map20
        		        this.aWMSLayers.push(iLayer);
        		    }
		        } catch(e){alert(e)}        
		    }
		}
    },
      
	/** 
     * @private
     * from WMSManager
     */
    findChildByName: function(tag,name) {
		if(!tag)return false;
		var x = tag.firstChild;
		while (x)
	    {
	    	if(x.nodeName==name) return x;
			else if(x==tag.lastChild)return null;
			else x=x.nextSibling;
	    }
	},
	
	/** 
     * @private
     * from WMSManager
     */
    findChildrenByName: function(tag,name) {
		if(!tag)return false;
		var nodes=tag.childNodes;
		var aNode = [];
		for (i=0;i<nodes.length;i++) {
			var x=tag.childNodes[i];
			if(x.nodeName==name) aNode.push(x) ;
		}
		
		return aNode;
	},
	
    /** @final @type String */
    CLASS_NAME: "OpenLayers.Control.myWMSManager"
});


 /** Sarissa derived getText
     *  
     * @private
     *
     * @param {Node} XML node
     * @param {int} deep recursion  
     */
	OpenLayers.Ajax.getText = function(oNode, deep){
	    var s = "";
	    var nodes = oNode.childNodes;
	    for(var i=0; i < nodes.length; i++){
	        var node = nodes[i];
	        var nodeType = node.nodeType;
	        if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
	            s += node.data;
	        } else if(deep == true
	                    && (nodeType == Node.ELEMENT_NODE
	                        || nodeType == Node.DOCUMENT_NODE
	                        || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
	            s += OpenLayers.Ajax.getText.getText(node, true);
	        };
	    };
	    return s;
	};
	
	/** Sarissa derived getParseErrorText
     *  
     * @private
     *
     * @param {Document} oDoc The target DOM document
     * @returns The parsing error description of the target Document in
     *          human readable form (preformated text)
     */
	OpenLayers.Ajax.PARSED_OK = "Document contains no parsing errors";
	OpenLayers.Ajax.PARSED_EMPTY = "Document is empty";
	OpenLayers.Ajax.PARSED_UNKNOWN_ERROR = "Not well-formed or other error";
	
	OpenLayers.Ajax.getParseErrorText = function(oDoc){
		//this is only the IE version from Sarissa	
	   var parseErrorText = OpenLayers.Ajax.PARSED_OK;
        if(oDoc && oDoc.parseError && oDoc.parseError.errorCode && oDoc.parseError.errorCode != 0){
            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 
                "\nLocation: " + oDoc.parseError.url + 
                "\nLine Number " + oDoc.parseError.line + ", Column " + 
                oDoc.parseError.linepos + 
                ":\n" + oDoc.parseError.srcText +
                "\n";
            for(var i = 0;  i < oDoc.parseError.linepos;i++){
                parseErrorText += "-";
            };
            parseErrorText +=  "^\n";
        }
        else if(oDoc.documentElement == null){
            parseErrorText = OpenLayers.Ajax.PARSED_EMPTY;
        };
        return parseErrorText;
	};
	
	/** 
	 * Sarissa derived Escape
	 * Escape the given string chacters that correspond to the five predefined XML entities
	 * @param sXml the string to escape
	 */
	OpenLayers.Ajax.escape = function(sXml){
	    return sXml.replace(/&/g, "&amp;")
	        .replace(/</g, "&lt;")
	        .replace(/>/g, "&gt;")
	        .replace(/"/g, "&quot;")
	        .replace(/'/g, "&apos;");
	};
	/** 
	 * Sarissa derived Unescape
	 * Unescape the given string. This turns the occurences of the predefined XML 
	 * entities to become the characters they represent correspond to the five predefined XML entities
	 * @param sXml the string to unescape
	 */
	OpenLayers.Ajax.unescape = function(sXml){
	    return sXml.replace(/&apos;/g,"'")
	        .replace(/&quot;/g,"\"")
	        .replace(/&gt;/g,">")
	        .replace(/&lt;/g,"<")
	        .replace(/&amp;/g,"&");
	};
	
	/** 
	 * Sarissa node values definition
	 * 
	 */
	if(!window.Node || !Node.ELEMENT_NODE){
	    Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
	};

