//<![CDATA[

// netlocator.js:
//   show subnet under cursor (involves slow hilbert curve unwinding)

/**
 * @requires OpenLayers/Control.js
 */

/**
 * Class: OpenLayers.Control.NetLocator
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */

OpenLayers.Control.NetLocator = OpenLayers.Class(OpenLayers.Control, {

    /**
     * Property: element
     * {DOMElement}
     */
    element: null,

    /**
     * APIProperty: suffix
     * {String}
     */
    suffix: '',
   
    /**
     * Constructor: OpenLayers.Control.NetLocator
     *
     * Parameters:
     * options - {DOMElement} Options for control.
     */
    initialize: function(options) {
        OpenLayers.Control.prototype.initialize.apply(this, arguments);
    },

    /**
     * Method: destroy
     */
     destroy: function() {
         if (this.map) {
             this.map.events.unregister('mousemove', this, this.mouseMove);
	     this.map.events.unregister('click', this, this.onClick);
         }
         OpenLayers.Control.prototype.destroy.apply(this, arguments);
     },

    /**
     * Method: draw
     * {DOMElement}
     */
    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this, arguments);

	// create layout
	this.loadContents();

	// populate div with current info
	this.redraw();

        return this.div;
    },

    /**
     * Method: redraw
     */
    redraw: function(evt) {
      this.mouseMove(evt);
    },

    /**
     * Method: loadContents
     * Set up the labels and divs for the control
     */
    loadContents: function() {
      //configure main div
      this.div.style.position = "absolute";
      this.div.style.top = "5px";
      this.div.style.marginTop = "5px";
      this.div.style.right = "5px";
      //this.div.style.rightMargin = "2px";
      this.div.style.fontSize = "small";
      this.div.style.backgroundColor = "transparent";
      //this.div.style.width = "70px";
      //this.div.style.padding="2px";
      this.div.style.zIndex = 2000;
      this.inputElem = document.createElement("input");
      this.inputElem.id = "inputip";
      this.inputElem.type = "text";
      //this.inputElem.focus = "true";
      this.inputElem.style.fontFamily = "Arial";
      //this.inputElem.style.display = "block";
      this.inputElem.style.fontSize="small";
      this.inputElem.fontWeight = "bold";
      this.inputElem.style.border = "1px solid black";
      this.inputElem.style.textAlign = "right";
      this.inputElem.style.width = "120px";
      this.inputElem.style.background = "white";
      this.inputElem.style.margin = "0px";
      this.inputElem.style.padding="2px";
      this.inputElem.ctrl = this;
      this.inputElem.zIndex = 2000;
      //this.inputElem.style.disabled = null;
      //this.inputElem.style.readonly = null;
      
      this.inputElem.keyinput=false; //flag used by NetLocator
      
      //this.map.events.register("mousedown", this.map, this.onMapRightClick);

      this.divEvents = new OpenLayers.Events(this, this.inputElem, ["click"], false, {includeXY: false});
      this.divEvents.on({ "click": this.onDivClick, "dblclick": this.onDivDblClick });
      this.map.events.register("mousedown", this, this.onMouseDown);

      this.handler = new OpenLayers.Handler.Keyboard(this.inputElem, { "keydown": this.keyPress });

      this.map.events.register('mousemove', this, this.mouseMove);
      this.div.appendChild(this.inputElem);
      this.activate();
    },

    onDivDblClick: function(evt) {
      if (this.inputElem.keyinput) {
	OpenLayers.Event.stop(evt);
	return;
      }
    },

    onMouseDown: function(evt) {
      if (OpenLayers.Event.isLeftClick(evt)) {
	this.onMapClick(evt);
      } else {
	if (evt.preventDefault) evt.preventDefault();
	this.onMapRightClick(evt);
      }
    },

    onMapRightClick: function(evt) {
      var ll = this.map.getLonLatFromPixel(evt.xy);
      if (!ll) return;

      var ip = this.getIPString(ll, this.map.netmask);
      if (ip == null) return;
      
      if (this.map.netbits < 32)
	ip += "/" + this.map.netbits;
      
      this.markIP(ip, false);
    },

    onDivClick: function(evt) { 
      this.inputElem.keyinput=true;
      this.inputElem.style.border="1px solid red";
      this.inputElem.value="";
      this.inputElem.focus();
      OpenLayers.Event.stop(evt);
    },

    onMapClick: function(evt) {
      if (this.inputElem.keyinput) {
	OpenLayers.Event.stop(evt);
	return;
      }

      //this.inputElem.keyinput=false;
      //this.inputElem.value="map"; 
    },

    mouseMove: function(evt) {
      if (this.inputElem.keyinput) return;
      if (evt == null) return;

      var ll = this.map.getLonLatFromPixel(evt.xy);
      if (!ll) return;

      var addr = this.getIPString(ll, this.map.netmask);
      this.inputElem.value = (addr) ? addr : ""; // "" needed for IE
      
      //if (this.map.netbits > 28)
      //	ptr.innerHTML += "<sup>&Dagger;</sup>";
      if (this.map.netbits < 32)
	this.inputElem.value += "/" + this.map.netbits;
    },

    keyPress: function(e) {
      this.keyinput=true; 
      this.style.border="1px solid red";
      var keycode;
      if (window.event) {
        e = window.event;
        keycode = e.keyCode;
      } else if(e.which) {
        keycode = e.which;
      }
      if (keycode == 13) {
	this.ctrl.markIP(this.value, true);
	this.value="";
	this.keyinput=false;
	this.style.border="1px solid black";

      }
    },

    getIPString: function(ll, mask) {
      if (ll.lon < 0 || ll.lat < 0 || ll.lon > 65536 || ll.lat > 65536) return null;

      ll.lat = 65536 - ll.lat;
      if (ll.lat == 65536) ll.lat = 65535; //edge effects
      if (ll.lon == 65536) ll.lon = 65535;

      var ull = hilbert_c2i(16, [ll.lat, ll.lon]);
      if (mask != null) ull.and1(mask); //mask (insignificant) host bits
      var o4 = ull.l & 0xff;
      ull.rshift1(8); // because ull.l is 31 bit 
      var o3 = ull.l & 0xff;
      var o2 = (ull.l >> 8) & 0xff;
      var o1 = (ull.l >> 16) & 0xff;
      return o1 + "." + o2 + "." + o3 + "." + o4;
    },

    markIP: function(iptxt, openpopup, pfix) {
      if (iptxt == null || iptxt.length == 0) return;
      if (!iptxt.match(/^\d{1,3}\/\d{1,2}$/)) {
	if (!iptxt.match(/^\d{1,3}\.\d{1,3}\/\d{1,2}$/)) {
	  if (!iptxt.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/)) {
	    if (!iptxt.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/)) {
	      if (window.XMLHttpRequest) {
		var xh = new XMLHttpRequest();
	      } else if (window.ActiveXObject) {
		var xh = new ActiveXObject("Microsoft.XMLHTTP");
	      } else {
		alert("Invalid IP address: " + iptxt);
		return;
	      }
	      var ctrl = this;
	      xh.onreadystatechange = function() {
		if (xh.readyState == 4) {
		  var ip = xh.responseText;
		  if (ip.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) {
		    ctrl.markIP(ip, true, "<b>"+iptxt+"</b><br>");
		  } else {
		    alert("Could not resolve: " + iptxt);
		  }
		}
	      };
	      xh.open("GET", "/cgi-bin/ant/resolve.pl?"+iptxt, true);
	      xh.send(null);
	      return;
	    }
	  }
	}
      }
      var netlen = iptxt.split("/");
      var net = netlen[0];
      var plen = 32;
      if (netlen.length > 1) {
	plen=netlen[1];
	if (plen < 1 || plen >32) return;
      }
      var o = net.split(".");
      var i, ull = new Ull(0,0);
      for (i = 0; i<4; ++i) {
	ull.lshift1(8);
	if (i < o.length) {
	  var x = parseInt(o[i]);
	  if (x > 255) return;
	  ull.or1(new Ull(0, x));
	}
      }
      if (32-plen > 0) {
	ull.rshift1(32-plen);
	ull.lshift1(32-plen);
      }
      var c1 = hilbert_i2c(16, ull);

      var llm = new OpenLayers.LonLat(c1[1], 65536-c1[0]);
      var popuptxt = (pfix)?pfix+iptxt:iptxt;
      this.addMarker(llm, popuptxt, openpopup);
      return;
    },

    addMarker: function(ll,iptxt,openinfo) {
      if (!this.ipmarkers) {
	this.ipmarkers = new OpenLayers.Layer.Markers("IP Markers");
	this.map.addLayer(this.ipmarkers);
	this.popupClass = OpenLayers.Class(OpenLayers.Popup.AnchoredBubble, {
            'autoSize': true
	    ,'maxSize': new OpenLayers.Size(140,45)
	  });
      }
      
      if (ll.lat == 65536) ll.lat = 65535; //edge effects
      if (ll.lon == 65536) ll.lon = 65535;

      ll.lat -= .5; // place in the middle of the pixel      
      ll.lon += .5; // (for zoom levels > 8)
      
      var feature = new OpenLayers.Feature(this.ipmarkers, ll);

      feature.popupClass = this.popupClass;
      feature.data.popupContentHTML = iptxt;
      feature.data.overflow = "hidden"; // or "auto"
      
      var marker = feature.createMarker();
      marker.netlocator = this;
      marker.feature = feature;

      marker.mouseDown = function(evt) {
	if (this.feature.popup == null) {
	  this.feature.createPopup(true);
	  this.netlocator.map.addPopup(this.feature.popup);
	  this.feature.popup.closeDiv.style.backgroundImage = 'url("close.png")';
	  this.feature.popup.closeDiv.style.backgroundRepeat = "no-repeat";
	  this.feature.popup.closeDiv.style.right = "0px";
	  this.feature.popup.setBackgroundColor("cyan");
	  this.feature.popup.setOpacity(1);
	  this.feature.popup.show();
	  //Use closebutton to remove marker
	  OpenLayers.Event.stopObservingElement(this.feature.popup.closeDiv);
	  OpenLayers.Event.observe(this.feature.popup.closeDiv, "click",
				   OpenLayers.Function.bindAsEventListener(marker.dblClick, marker));
	} else {
	  this.feature.popup.toggle();
	}
	if (evt) OpenLayers.Event.stop(evt);
      };

      marker.dblClick = function (evt) {
	this.netlocator.ipmarkers.removeMarker(this);
	this.feature.destroy(); 
	OpenLayers.Event.stop(evt);
      };

      marker.events.register("mousedown", marker, marker.mouseDown);
      //marker.events.register("dblclick",  marker, marker.dblClick);
      
      this.ipmarkers.addMarker(marker);
      if (openinfo) {
	marker.mouseDown();
	this.map.panTo(ll);
      }
    },


    CLASS_NAME: "OpenLayers.Control.NetLocator"
  });

//]]>
