/**
 * Class: OGIS.Geocoder
 * Geocoder locates a location based on the given input address parameters.
 *
 * Inherits from:
 *  - <OpenLayers.Class>
 */

OGIS.Geocoder = OGIS.Class({

    /**
     * APIProperty: street
     * {String} street address
     */
	street: "",

    /**
     * APIProperty: crossstreet
     * {String} cross street address <optional>
     */
	crossStreet: "",

    /**
     * * APIProperty: city
     * {String} name of the city
     */
	city: "",

    /**
     * * APIProperty: zip
     * {String} zip code for the location
     */
	zip: "",

     /**
     * * APIProperty: locateStreetIfAddrNotFound
     * {boolean} <true/false> [defaults to true]
     */
	locateStreetIfAddrNotFound: true,

     /**
     * APIProperty: state
     * {String} 2 letter state abbreviation[defaults to NJ]
     */
	state: "NJ",

     /**
     * APIProperty: projectionID
     * {String} ESRI coord system [defaults to "4269" (geographic coords) -- "102711"  (NJ State Plane coords)]
     */
	projectionID: "102711",

     /**
     * Property: processRec
     * {String} One of the record numbers from the multiple matches that were returned by the searchLocation method.
     * On submitting the record number, the geocoding process will be continued to locate the selected match.
     */
    processRec : "",

     /**
     * APIProperty: gcComponentUrl
     * {String} url to the associated servlet component of OIT_LocationSearch web service
     */
	gcComponentUrl: "http://vega10.pa.state.nj.us/OIT_LocationSearch/servlet/geocode",

     /**
     * APIProperty: callBackFunction
     * {String} The name of the function that handles the results. The results returned as a json object.
     */
	callBackFunction: null,

	afterZoomToPoint: null,
	afterZoomToPolygon: null,

     /**
     * APIProperty: resultsDiv
     * {String} the div tag id. The formatted results displayed in this div.
     * NOTE: Either callBackFunction name or resultsDiv are required to handle the results.
     */
    resultsDiv : "",

     /**
     * APIProperty: zoomLevel
     * {number} Allows user to override the zoom level to which the map is zoomed after the point coordinates are returned.
     */
	zoomLevel : 7,

    /**
     * APIProperty: map
     * {Object} user must specify map if OperLayers is used.
     */
    map : null,

    /**
     * APIProperty: icon
     * {<OpenLayers.Icon>} OpenLayers.Icon object that users can specify as the marker icon for a point location.
     */
    icon : null,

    /**
     * APIProperty: markerLayer
     * {<OpenLayers.Layer>} OpenLayers.Layer object that users can specify on which the icons will be placed.
     */
    markerLayer: null,

    /**
     * APIProperty: markerVisible
     * {boolean} - <true/false> user could choose not to show icon when zoomed to a point location.
     */
    markerVisible : true,

    /**
     * APIProperty: markerInLayerList
     * {boolean} - <true/false> could choose if not to list the marker in LayerList.
     */
    markerInLayerList : true,

    /**
     * APIProperty: indexInLayerList
     * {number} - user can specify the z-index of the icon layer in the LayerList.
     */
    indexInLayerList : null,

	/**
     * Property: marker
     * {Object} - ID of marker that shows the current geocoded location. used to delete old and identify new locations
     */
    marker : null,

	/**
     * Property: XSSBroker
     * {<XSSBroker>} - XSSBroker used to communicate with geocoding service
     */
    XSSBroker : null,

    /**
     * Property: JsonResult
     * {String} - Response from geocoding service
     */
    JsonResult : null,

    /**
     * Constructor: OGIS.Geocoder
     *
     * Parameters:
     * element - {DOMElement}
     * options - {Object}
     */

    initialize: function (options) {
        // We do this before the extend so that instances can override
        // className in options.
        OGIS.Util.extend(this, options);

        this.XSSBroker = new OGIS.XSSBroker();
    },

    /**
     * APIFunction: searchLocation
     * Makes a call to a web service(that supports geocoding process) with the
     * input Address parameters. A valid input address could be street, city, zip, state (OR)
     * street, city, state (OR) street, zip, state (OR) city, state (OR) zip, state.
     *
     * Parameters:
     * street - {String}
     * crossstreet - {String}
     * city - {String}
     * zip - {String}
     * state - {String}
     * resultsDiv - {String} Either resultsDiv or callBackFunction are required to handle the results
     * callBackFunction - {String} Either resultsDiv or callBackFunction are required to handle the results
     * projectionID - {String}
     * gcComponentUrl - {String}
     * options - {Object} A javascript collection with all the above specified parameters.
     *
     * Returns:
     * {JSON object} Results that may contain a) the details of the location(s) *OR* b) possible
     * multiple matches based on the input address *OR* c) zero results *OR* d) error message.
     * If multiple matches are returned, one of the matches should be selected to continue
     * and finish the geocoding process.
     */

    searchLocation : function (options){
         OGIS.Util.extend(this,options);
         if (!this.validateInputParams()){
            return false;
         }
         var txt = "{gcComponentUrl}?street={street}&cross_street={crossStreet}&city={city}&zip={zip}&state={state}&locateStreetIfAddrNotFound={locateStreetIfAddrNotFound}&projectionId={projectionID}&processRec=&getError=false&output=json";
         var gcUrl = OGIS.String.supplant(txt,this);
         if ($(this.resultsDiv) != null){
            $(this.resultsDiv).innerHTML = "";
			$(this.resultsDiv).className = $(this.resultsDiv).className + " OGIS_PleaseWait";
         }

         this.XSSBroker.sendRequest(this, this.processResponse, gcUrl);
    },

    /**
     * APIFunction: chooseRecFromMultipleMatches
     * Accepts the record number from one of the possible multiple matches and call the
     * web service again to further continue the geocoding process of the selected record.
     *
     * Parameters:
     * processRec - The record number from one of the multiple matches that were returned by searchLocation method.
     * options - {Object}. This method Uses the javascript collection with all the specified parameters that was
     * provided to the searchLocation method when the geocoding process started.
     *
     * Returns:
     * {JSON object} Results that may contain a) the details of the location(s) *OR* b) possible
     * multiple matches based on the input address *OR* c) zero results *OR* d) error message.
     */

    chooseRecFromMultipleMatches : function (rNum){
         this.processRec = rNum;
         if (!this.validateInputParams()){
            return;
         }
         if (this.processRec == "" || (this.processRec.indexOf("m") == -1 && this.processRec.indexOf("d") == -1)){
            OGIS.msgAlert('','processRec should be populated with the record number of the selected record from multiple matches');
            return;
         }
         var txt = "{gcComponentUrl}?street={street}&cross_street={crossStreet}&city={city}&zip={zip}&state={state}&locateStreetIfAddrNotFound={locateStreetIfAddrNotFound}&projectionId={projectionID}&processRec={processRec}&getError=false&output=json";
         var gcUrl = OGIS.String.supplant(txt,this);
         this.XSSBroker.sendRequest(this, this.processResponse, gcUrl);
    },

    ////////////////////////////////////////////////////////////////////////////
    // A Private Method: validateInputParams
    // Validates the input parameters.
    //
    // Returns:
    // boolean - true in case if the input parameters are valid else false.
    //
    ////////////////////////////////////////////////////////////////////////////
     validateInputParams : function (){
         if ((this.street == "" && this.crossStreet == "" && this.city == "" && this.zip == "") || (this.street != "" && this.city == "" && this.zip == "")){
            OGIS.msgAlert('','Street, City, Zip, State (OR) Street, Zip, State (OR) City, State (OR) Zip, State are required.');
            //alert("Street, City, Zip, State (OR) Street, Zip, State (OR) City, State (OR) Zip, State are required.");
            return false;
         }

         if (this.street != "" && (this.street.charAt(0) == " " || this.street.indexOf(" ") == -1)){
            OGIS.msgAlert('','Please enter a valid Street from starting position.');
            return false;
         }

         if (this.city != "" && this.city.charAt(0) == " "){
            OGIS.msgAlert('','Please enter the City from starting position.');
            return false;
         }

         if (this.zip != ""){
            if (this.zip.length == 5){
                var re = new RegExp("\\d{5}");
                if (re.exec(this.zip) == null){
                   OGIS.msgAlert('','Zip must be a 5 digit number');
                   return false;
                }
            }
            else {
                 OGIS.msgAlert('','Zip must be a 5 digit number');
                 return false;
            }
         }

         if (this.state != ""){
            if (this.state.length == 2){
                var re = new RegExp("[^A-Za-z]");
                if (re.exec(this.state) != null){
                   OGIS.msgAlert('','State must be a two character abbreviation(exa: NJ or PA or NY).');
                   return false;
                }
            }
            else {
                 OGIS.msgAlert('','State must be a two character abbreviation(exa: NJ or PA or NY).');
                 return false;
            }
         }
         else {
              OGIS.msgAlert('','State must be a two character abbreviation(exa: NJ or PA or NY).');
              return false;
         }
         if (this.projectionID != "" && this.projectionID != "4269" && this.projectionID != "102711"){
            OGIS.msgAlert('','The projectionID must be either 4269(Geometric projectionID) or 102711 (NJ State plane projectionID)');
            return false;
         }
         return true;
     },

    /**
     *
     * Function: processResponse
     * Either binds the response(a json object) obtained from the geocoding web service to the
     * callBackFunction or displays the results in the resultsDiv.
     *
     * Parameters:
     * jsonData - the json object returned by searchLocation or chooseRecFromMultipleMatches methods.
     *
     * Returns:
     * jsonObject - or - results formatted to display in resultsDiv.
     *
     */
    processResponse : function (jsonData){
         //var myFormat = new OpenLayers.Format.JSON();
         //var myTxt = myFormat.write(jsonData, true);
         //alert(myTxt);

         this.JsonResult = jsonData;

		 if (this.resultsDiv != "" && $(this.resultsDiv)!= null) {
              this.displayResults();
         }

		 if (this.callBackFunction){
            this.callBackFunction(this.JsonResult);
         }

    },

    /**
     *
     * APIFunction: zoomToPolygon
     * An abstract method to handle the extents of the location if returned by the geocoding process
     * instead of the coordinates of the location. This method and should be overridden by the user.
     *
     * Parameters:
     * minx - minx of extent of the location
     * miny - miny of extent of the location
     * maxx - maxx of extent of the location
     * maxy - maxy of extent of the location
     *
     */
    zoomToPolygon : function (minx,miny,maxx,maxy){
              if (this.map){
                 //Move/Pan to minX,minY,maxX,maxY
                 this.map.zoomToExtent(new OpenLayers.Bounds(minx,miny,maxx,maxy));
              }
              else {
                   OGIS.msgAlert('','Method zoomToPolygon needs to be overridden');
              }
              if (this.afterZoomToPolygon){
                 this.afterZoomToPolygon();
              }
    },

    /**
     *
     * APIFunction: zoomToPoint
     * An abstract method to handle the point coordinates of the location returned by the geocoding process.
     * This method should be overridden by the user.
     *
     * Parameters:
     * x - the x coordinate of the location
     * y - the y coordinate of the location
     * LocAddr - the address of the location
     *
     */
	SHADOW_Z_INDEX: 10,
	MARKER_Z_INDEX: 11,
    zoomToPoint : function (x,y,LocAddr) { //Modified the method signature on 7/8/08

		if (this.map){
			if (this.icon){
				var markerStyle = new OpenLayers.Style({
					// Set the external graphic and background graphic images.
					externalGraphic: this.icon.url,
					backgroundGraphic: this.icon.bkg.url,
					// Makes sure the background graphic is placed correctly relative to the external graphic.
					backgroundXOffset: this.icon.bkg.offset.x,
					backgroundYOffset: this.icon.bkg.offset.y,
					// Graphic specific options
					graphicWidth: this.icon.size.w,
					graphicHeight: this.icon.size.h,
					graphicOpacity: 1,
					graphicXOffset: this.icon.offset.x,
					graphicYOffset: this.icon.offset.y,
					graphicZIndex: this.MARKER_Z_INDEX,
                    backgroundGraphicZIndex: this.SHADOW_Z_INDEX
				});
			} else {
				var markerStyle = new OpenLayers.Style({
					// Set the external graphic and background graphic images.
					externalGraphic: OpenLayers.Util.getImagesLocation() + "marker.png",
					backgroundGraphic: OpenLayers.Util.getImagesLocation() + "marker-shadow.png",
					// Makes sure the background graphic is placed correctly relative to the external graphic.
					backgroundXOffset: 0,
					backgroundYOffset: -25,
					// Graphic specific options
					graphicWidth: 21,
					graphicHeight: 25,
					graphicOpacity: 1,
					graphicXOffset: -11,
					graphicYOffset: -25,
					graphicZIndex: this.MARKER_Z_INDEX,
                    backgroundGraphicZIndex: this.SHADOW_Z_INDEX
				});
			}

			if (!this.markerLayer){
				this.markerLayer = new OpenLayers.Layer.Vector("Geocoded Locations",
					{scales:[4000000,1], displayInLayerSwitcher : this.markerInLayerList, rendererOptions: {yOrdering: true},
						styleMap: new OpenLayers.StyleMap({
							"default": markerStyle})
					}
				);

                 this.map.addLayer(this.markerLayer);
                 if (this.indexInLayerList != null){
                    this.map.setLayerIndex(this.markerLayer, this.indexInLayerList);
                 }
            }

              //move/pan to X,Y
			this.marker = null;
            this.markerLayer.destroyFeatures();

            if (this.markerVisible){
				this.marker = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x,y), {locationAddress: LocAddr});
				this.markerLayer.addFeatures([this.marker]);
		         //this.markerId = new OpenLayers.Marker(new OpenLayers.LonLat(x,y),this.icon.clone());
		         //this.markerId.locationAddress = LocAddr;
                 //this.markerLayer.addMarker(this.markerId);
            }
		    this.map.setCenter(new OpenLayers.LonLat(x, y), this.zoomLevel,false,true);
		} else {
              OGIS.msgAlert('','Method zoomToPoint needs to be overridden');
        }
        if (this.afterZoomToPoint){
			this.afterZoomToPoint();
		}
/*          if (this.map){
              if (!this.markerLayer){
                 //Add layer to the map with options from this
                 this.markerLayer = new OpenLayers.Layer.Markers( "Geocoded Locations", {
                        scales:[4000000,1],displayInLayerSwitcher : this.markerInLayerList}
                 );
                 this.map.addLayer(this.markerLayer);
                 if (this.indexInLayerList != null){
                    this.map.setLayerIndex(this.markerLayer, this.indexInLayerList);
                 }
              }
              //move/pan to X,Y
              if (this.markerId){
                 this.markerLayer.removeMarker(this.markerId);
                 this.markerId.destroy();
			  }
              if (this.markerVisible){
		         this.markerId = new OpenLayers.Marker(new OpenLayers.LonLat(x,y),this.icon.clone());
		         this.markerId.locationAddress = LocAddr;
                 this.markerLayer.addMarker(this.markerId);
              }
		      this.map.setCenter(new OpenLayers.LonLat(x, y), this.zoomLevel,false,true);
		  }
		  else {
              OGIS.msgAlert('','Method zoomToPoint needs to be overridden');
          }
          if (this.afterZoomToPoint){
             this.afterZoomToPoint();
          }
*/
    },

    /**
     *
     * Function: displayResults
     * Called by the processResponse method to format the results and populate
     * the resultsDiv with the formatted results.
     *
     *
     */
    displayResults : function(){
	     //var destDIV = document.getElementById(ResultsDivName);
	     var destDIV = $(this.resultsDiv);

         //Default Messages
         var Messages = {
             'ERROR' : 'Error occured while processing your request.',
             'ZERO' : 'Your query returned Zero Results.',
             'INSUFFICIENT' : 'Insufficent Data. State AND [(address, city, zip) OR (address, city) OR (address, zip) OR city OR Zip] are required.',
             'WARNING' : ''
         };

         //Removing any previously attached table from resultsDiv
         try {
	         destDIV.innerHTML = "";
			 destDIV.className = destDIV.className.replace("OGIS_PleaseWait", "");
	     }
	     catch (x){}

         //Creating a table
	     var table = document.createElement('table');
	     var tbody = table.appendChild(document.createElement('tbody'));
	     var tr, td;
	     var ax = true;
	     table.id = 'topTable';
	     table.className = 'OGIS_GC_Results_Table';
	     //Table width changed from 100% to 90% on 7/3/08
	     table.width = '90%';
	     table.cellSpacing = '0';
	     table.cellPadding = '0';

         //=============================================
	     //Checking the FinalResult of Geocoding process
	     //=============================================
	     var FinalResultObtained = this.JsonResult.FinalResult.toUpperCase();
	     var WarningMsg = "";
	     if (FinalResultObtained.indexOf(" ") != -1){
	        if (FinalResultObtained.indexOf("WARNING") != -1){
	            WarningMsg = this.JsonResult.FinalResult;
	            WarningMsg = WarningMsg.substring(WarningMsg.indexOf(" "),WarningMsg.length);
	        }
	        FinalResultObtained = FinalResultObtained.substring(0,FinalResultObtained.indexOf(" "));
	     }

         //==============================================================================
         //Checking the cases of Zero Results, Error occurence, Insufficient data message
         //==============================================================================
         if (Messages[FinalResultObtained] != null){

            //Adding the Header
	        tr = tbody.appendChild(document.createElement('tr'));
	        td = tr.appendChild(document.createElement('td'));
	        td.className = 'OGIS_GC_Header';
	        td.innerHTML = "Message:";

            //Adding the content
	        tr = tbody.appendChild(document.createElement('tr'));
	        tr.className = 'OGIS_GC_Rec1 OGIS_GC_RecLast';
	        td = tr.appendChild(document.createElement('td'));
	        if (Messages[FinalResultObtained] != null){
	           if (WarningMsg != ""){
	               td.innerHTML = WarningMsg;
	           }
	           else {
	                td.innerHTML = Messages[FinalResultObtained];
	           }
	        }
	        else {
	             td.innerHTML = Messages.ZERO;
	        }

	        //Attaching the created table to the resultsDiv
	        destDIV.appendChild(table);
	        return;
	    }
	    //========================
	    //Looping thru the Results
	    //========================
	    else if (this.JsonResult.ResultSet != null){
	         var GeneralHeaderAdded = false;
	         var MatchesHeaderAdded = false;
	         var DidYouMeanHeaderAdded = false;
	         //====================
             //Single Record Return
             //====================
	         if (FinalResultObtained == "TRUE" && this.JsonResult.ResultSet.length == 1){

                //Adding the Header
	            tr = tbody.appendChild(document.createElement('tr'));
	            td = tr.appendChild(document.createElement('td'));
	            td.className = 'OGIS_GC_Header';
	            td.innerHTML = "Results:";

	            //Adding the content
	            tr = tbody.appendChild(document.createElement('tr'));
	            tr.className = 'OGIS_GC_Rec1 OGIS_GC_RecLast';
	            ax = false;
	            td = tr.appendChild(document.createElement('td'));
	            td.innerHTML = this.JsonResult.ResultSet[0].FriendlyDisplay;

	            //Attaching the created table to the resultsDiv
	            destDIV.appendChild(table);

	            if (this.JsonResult.ResultSet[0].minx != null){
	               this.zoomToPolygon(this.JsonResult.ResultSet[0].minx, this.JsonResult.ResultSet[0].miny, this.JsonResult.ResultSet[0].maxx, this.JsonResult.ResultSet[0].maxy);
	            }
	            else {
	                 this.zoomToPoint(this.JsonResult.ResultSet[0].x, this.JsonResult.ResultSet[0].y, this.JsonResult.ResultSet[0].FriendlyDisplay);
	            }
            }
            //=======================
            //Multiple Records Return
            //=======================
            else {
                for (var i=0;i<this.JsonResult.ResultSet.length;i++) {
                     var IfLastRecordAddThisStyle = "";
                     if (i == (this.JsonResult.ResultSet.length - 1)){
                         IfLastRecordAddThisStyle = " OGIS_GC_RecLast";
                     }

                     //Adding the Header
                     if (FinalResultObtained == "TRUE"){
		                if (!GeneralHeaderAdded){
	                        tr = tbody.appendChild(document.createElement('tr'));
	                        td = tr.appendChild(document.createElement('td'));
	                        td.colSpan = '2';
	                        td.className = 'OGIS_GC_Header';
	                        td.innerHTML = "Multiple Results:";
	                        GeneralHeaderAdded = true;
		                }
		             }
                     else if (FinalResultObtained == "FALSE"){
                          if ((!MatchesHeaderAdded && this.JsonResult.ResultSet[i].RecNumber.indexOf("m") != -1) || (!DidYouMeanHeaderAdded && this.JsonResult.ResultSet[i].RecNumber.indexOf("d") != -1)){
	                         tr = tbody.appendChild(document.createElement('tr'));
	                         td = tr.appendChild(document.createElement('td'));
	                         td.colSpan = '2';
	                         if (!MatchesHeaderAdded && this.JsonResult.ResultSet[i].RecNumber.indexOf("m") != -1){
	                            td.className = 'OGIS_GC_Matches_Header';
	                            td.innerHTML = "100% Matches:";
	                            MatchesHeaderAdded = true;
                             }
	                         else if (!DidYouMeanHeaderAdded && this.JsonResult.ResultSet[i].RecNumber.indexOf("d") != -1){
	                            td.className = 'OGIS_GC_DidYouMean_Header';
	                            td.innerHTML = "Did You Mean:";
	                            DidYouMeanHeaderAdded = true;
	                         }
		                  }
                     }

                     //Adding the content
                     tr = tbody.appendChild(document.createElement('tr'));
		             tr.onmouseover = this.trSelect;
		             tr.onmouseout = this.trSelect;

                     //Multiple Final Results
		             if (FinalResultObtained == "TRUE"){
		                if (this.JsonResult.ResultSet[i].minx != null){
		                   tr.onclick = OGIS.Function.bind(this.zoomToPolygon, this, this.JsonResult.ResultSet[i].minx, this.JsonResult.ResultSet[i].miny, this.JsonResult.ResultSet[i].maxx, this.JsonResult.ResultSet[i].maxy);
		                }
		                else {
		                     tr.onclick = OGIS.Function.bind(this.zoomToPoint, this, this.JsonResult.ResultSet[i].x, this.JsonResult.ResultSet[i].y, this.JsonResult.ResultSet[i].FriendlyDisplay);
                        }
		             }
		             //Multiple matches and did you mean listing
		             else {
		                  if (!DidYouMeanHeaderAdded && this.JsonResult.ResultSet[i+1] != null && this.JsonResult.ResultSet[i+1].RecNumber.indexOf("d") != -1 && (IfLastRecordAddThisStyle == "" || IfLastRecordAddThisStyle != "OGIS_GC_RecLast")){
	                          IfLastRecordAddThisStyle = " OGIS_GC_RecLast";
	                      }
		                  tr.onclick = OGIS.Function.bind(this.chooseRecFromMultipleMatches, this, this.JsonResult.ResultSet[i].RecNumber);
		             }
		             if(ax){
			             tr.className = 'OGIS_GC_Rec1';
			             ax = false;
		             } else {
			             tr.className = 'OGIS_GC_Rec2';
			             ax = true;
		             }

		             tr.className = tr.className + IfLastRecordAddThisStyle;

		             td = tr.appendChild(document.createElement('td'));
		             td.innerHTML = this.JsonResult.ResultSet[i].FriendlyDisplay;
		             td = tr.appendChild(document.createElement('td'));
					 td.innerHTML = "";
                }
            }

	        //Attaching the created table to the resultsDiv
	        destDIV.appendChild(table);
	        return;
	    }
	    //=================================================
	    // In case nothing happened so far with the results
	    //=================================================
	    else {
	        //Adding the Header
	        tr = tbody.appendChild(document.createElement('tr'));
	        td = tr.appendChild(document.createElement('td'));
	        td.className = 'OGIS_GC_Header';
	        td.innerHTML = "Message:";

            //Adding the Content
	        tr = tbody.appendChild(document.createElement('tr'));
	        tr.className = 'OGIS_GC_Rec1 OGIS_GC_RecLast';
	        td = tr.appendChild(document.createElement('td'));
	        td.innerHTML = Messages.ZERO;

	        //Attaching the created table to the resultsDiv
	        destDIV.appendChild(table);
	        return;
	    }
     },

     trSelect: function(){
	       if(this.className.indexOf("OGIS_GC_Select") == -1){
		      this.className = this.className + " OGIS_GC_Select";
	       } else {
		          this.className = this.className.replace("OGIS_GC_Select", "");
	       }
     },

     CLASS_NAME: "OGIS.Geocoder"
});

function changeDiv(wdiv) {	thediv = document.getElementById(wdiv);	if(thediv.className == 'folderclosed'){		thediv.className = 'folderopen';	} else if (thediv.className == 'folderopen'){		thediv.className = 'folderclosed';		}}

//http://www.domedia.org/oveklykken/css-transparency.php
