// ---------------------------------------------------------------------------
// (c) 2003 Geotalk, Hans Martin Mohn
//
// Code for handling a map loaded using Publisher's GetHTML command.
// It assumes a page organized as the diagram below, ie it must contain an
// IFRAME where "src" can be manipulated in order to navigate the map.
//
//     <html> page (html or aspx)
//    +--------------------------------------------------+
//    |    <iframe>                                      |
//    |   +------------------------------------------+   |
//    |   |  GeoServe:GetHTML?...                    |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   |                                          |   |
//    |   +------------------------------------------+   |
//    |                                                  |
//    +--------------------------------------------------+
//
// * To connect this code to the above structure, call gtBeMapJS(iframe,...);
// * To

// ---------------------------------------------------------------------------

gtAssert("gtEventHandler  != null");
gtAssert("gtNavigateStack != null");
gtAssert("gtUrl           != null");
gtAssert("gtMatrix        != null");

gtIgnoreHistory = 1;

function gtBeMapJS(m, tooltip_marker) // m must be the <iframe> from the figure above
{
  m.onBeforeDrawMap    = new gtEventHandler();
  m.onDrawStateChanged = new gtEventHandler();
  m.m_tool             = null;
  m.m_url              = null;
  m.m_rect             = null;
  m.m_marker           = null;     // Marker that can show where the current object is
  m.m_matrix           = null;
  m.m_inverse          = null;
  m.m_coord_sys        = "";
  m.m_min_scale        = 200;      // TODO: Shouldn't be hard-coded!!!!
  m.m_max_scale        = 20000000;
  m.m_busy             = false;
  m.m_save_cursor      = "";
  m.m_extent_user      = null;
  m.m_extent_coord_sys = null;
  m.m_navigate_stack   = new gtNavigateStack();
  m.m_tooltip_marker   = tooltip_marker;
  m.m_padding          = 1;
  m.m_gtx_path         = "";

  // Support for loading objects  
  m.onObjectsLoaded    = new gtEventHandler();
  m.onObjectsSaved     = new gtEventHandler();
  m.m_default_ids      = "xdAllInside";
  m.m_alt_obj_themes   = null;      // If set, used as obj_themes-parameter for the loadObjects-call
  m.m_objects_dom      = null;      // Any objects loaded by the loadObjects method (as a DOM fragment)
  m.m_objects_text     = "";



  m.setBorderWidth = function gtMapJS_setBorderWidth(w)
  {
    this.style.borderWidth = w + "px";
    this.m_padding = w;
  }; // end setBorderWidth()
  

  // This method is called by the template file when it has loaded!
  m.onMapLoaded = function(url_string, matrix_string, img, rect, marker, pan_urls, icon, coord_sys)
  {
  //  alert("gtMapJS::onMapLoaded: " + url_string);
  //  top.gtTrace("gtMapJS::onMapLoaded: " + url_string + "\n");
    this.m_url            = new gtUrl(url_string);
    this.m_matrix         = new gtMatrix(matrix_string);
    this.m_inverse        = this.m_matrix.inverse();
    this.m_img            = img;
    this.m_rect           = rect;
    this.m_marker         = marker;
    this.m_icon           = icon;
    this.m_pan_urls       = pan_urls;
    this.m_coord_sys      = coord_sys;
//    alert(coord_sys);
    this.m_width          = this.m_url.getParam("w");
    this.m_height         = this.m_url.getParam("h");
    this.m_viewport_user  = this.m_inverse.transformPointsString("0,0," + this.m_width + ",0," + this.m_width + "," + this.m_height + ",0," + this.m_height);
    this.m_marker.title   = this.m_tooltip_marker;
    this.showMarker();

    addGTHandlers(img);
    var closure = this.contentWindow;
    img.m_map = this; // Enable us to access this iframe from img's event handlers
    img.gtClick     = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.click     (evt || mutateIEEventToGT(closure.event)); }
    img.gtMouseDown = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.buttonDown(evt || mutateIEEventToGT(closure.event)); }
    img.gtMouseUp   = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.buttonUp  (evt || mutateIEEventToGT(closure.event)); }
    img.gtMouseMove = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.mouseMove (evt || mutateIEEventToGT(closure.event)); }
    img.gtMouseOver = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.enter     (evt || mutateIEEventToGT(closure.event)); }
    img.gtMouseOut  = function(evt) { if (this.m_map.m_tool) return this.m_map.m_tool.leave     (evt || mutateIEEventToGT(closure.event)); }
    this.setBusy(false);
    if (this.m_tool != null)
      this.m_tool.update();
    this.onDrawStateChanged.raise("idle", this.m_url, this.m_viewport_user);
  }; // end onMapLoaded()


  m.getViewportDevice = function()
  {
    var w = gtGetWidth (this) - 2 * this.m_padding;
    var h = gtGetHeight(this) - 2 * this.m_padding;
    return "0,0 " + w + ",0 " + w + "," + h + " 0," + h;
  }; // end getViewportDevice()


  m.device2User = function(device)
  {
    return this.m_inverse.transformPointsString(device);
  }; // end device2User()


  m.user2Device = function(user)
  {
    return this.m_matrix.transformPointsString(user);
  }; // end user2Device()



  // ----------------------------------------------------------------------------
  // Cursor handling
  // ----------------------------------------------------------------------------
  m.setCursor = function(cursor_name)
  {
    this.m_save_cursor = cursor_name;
    try
    {
      if (!this.m_img || !this.m_img.style)
        return;
    }
    catch (e)
    {
      return;
    }
    if (!this.m_busy)
    {
      this.m_img.style.cursor = cursor_name;
      this.m_rect.style.cursor = cursor_name;
    }
  } // end setCursor()



  m.setBusy = function(busy)
  {
    this.m_busy = busy;
    try
    {
      if (!this.m_img || !this.m_img.style)
        return;
    }
    catch (e)
    {
      return;
    }
      
    if (!busy)
    {
      this.m_img.style.cursor  = this.m_save_cursor;
      this.m_rect.style.cursor = this.m_save_cursor;
    }
    else
    {
      this.m_img.style.cursor  = "wait";
      this.m_rect.style.cursor = "wait";
    }
  }; // end setBusy()



  // ----------------------------------------------------------------------------
  // Tool operations
  // ----------------------------------------------------------------------------

  m.selectToolByName = function(tool_name)
  {
    switch (tool_name)
    {
      case "zoom":
      this.selectTool(g_tool_zoom);
      break

      case "pan":
      this.selectTool(g_tool_pan);
      break;
    }
  } // end selectToolByName()


  m.selectTool = function(tool)
  {
    var prev = this.m_tool;
    if (this.m_tool)
      this.m_tool.deselect(this, tool); // Pass a pointer to the tool that is about to be selected
    this.m_tool = tool;
    if (this.m_tool != null)
      this.m_tool.select(this, prev);   // Pass a pointer to the previously selected tool
    return prev;
  }; // end selectTool()


  // Redraw the map. If url is not given use the last url
  m.showMap = function(url, history)
  {
//    alert("showMap(" + url.toString() + ")");
    if (!url)
      url = this.m_url;
//  top.gtTraceLine("gtMapJS::showMap: " + url.toString());

    // Allow clients to look at and/or change the map url
    // Client must change the contents of the passed url for changes to have any effect!
    this.onBeforeDrawMap.raise(url);

    if (history != gtIgnoreHistory)
      this.m_navigate_stack.addUrl(url);

    var w = gtGetWidth (this) - 2 * this.m_padding;
    var h = gtGetHeight(this) - 2 * this.m_padding;
    if (w > 20 && h > 20)
    {
      this.setBusy(true);
      url.setParam("w", w);
      url.setParam("h", h);
      this.m_url = url;
      this.onDrawStateChanged.raise("drawing", this.m_url, this.m_viewport_user);
      this.refreshMap(url);
    }
    else
    {
//      alert("showMap: too small!");
      // Just remember url (we are probably not visible right now!)
      this.m_url = url;
    }
  }; // end showMap()

  m.cmdNavigate = function(cmd)
  {
    if (cmd == "f")
    {
      if (this.m_navigate_stack.nextOk())
        this.showMap(this.m_navigate_stack.getNext(), gtIgnoreHistory);
      return;
    }
    else if (cmd == "b")
    {
      if (this.m_navigate_stack.prevOk())
        this.showMap(this.m_navigate_stack.getPrev(), gtIgnoreHistory);
      return;
    }

    var cmds = new Array('in', 'out', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw');
    for (var i = 0; i < cmds.length; i++)
    {
      if (cmd == cmds[i])
      {
        var url = new gtUrl(this.m_pan_urls[i]);
        this.showMap(url);
        return;
      }
    }
  } // end cmdNavigate()


  m.refreshMap = function(url)
  {
//    alert(url.toString());
//    top.gtTrace("gtMapJS::refreshMap()\n");
    url.setService("GetHTML");
    if (this.m_gtx_path)
      url.setParam("tag", m.m_gtx_path);  // Hack to enable us to specify where the template file can find gtx
      
    var t = url.getParam("t");
    if (t == undefined || t + "" == "")
      alert("Cannot get HTML without the t= parameter set!");
    var prefix = window.location.protocol + "//" + window.location.hostname + "/GeoServe%3A";
    this.src = prefix + url.toString();
//    alert(this.src);
  }; // end refreshMap()


  m.setScale = function(scale)
  {
//    top.gtTrace("gtMapJS::setScale(" + scale + ")\n");
    this.m_url.setParam("s", scale);
    this.showMap(this.m_url);
  }; // end setScale()


  m.multiplyScaleByFactor = function(factor)
  {
//    top.gtTrace("gtMapJS::multiplyScaleByFactor(" + factor + ")\n");
    var cur_scale = parseFloat(this.m_url.getParam("s"));
    this.m_url.setParam("s", factor * cur_scale);
    this.showMap(this.m_url);
  }; // end multiplyScaleByFactor()


  m.resize = function(w, h)
  {
//    top.gtTrace("gtMap::resize(" + w + ", " + h + ")\n");
    gtSetWidth (this, w);
    gtSetHeight(this, h);
    if (this.m_url)
    {
      this.m_url.setParam("w", w);
      this.m_url.setParam("h", h);
      this.showMap(this.m_url);
    }
  }; // resize()


  m.setMarker = function(extent_user, extent_coord_sys)
  {
    this.m_extent_user      = extent_user;
    this.m_extent_coord_sys = extent_coord_sys;
    this.showMarker();
  }; // end setMarker()



  m.showMarker = function()
  {
    if (!this.m_extent_user)
    {
      if (this.m_marker)
        gtSetVisibility(this.m_marker, "hidden");
      return;
    }

    var ext;
    overview_coord_sys = this.m_url.getParamDef("dst", "TM84(" + this.m_url.getParam("x") + ")");
    if (this.m_extent_coord_sys != overview_coord_sys)
    {
      alert("Different coordinate systems in detail and overview map not supported!! (" + this.m_extent_coord_sys + " and " + overview_coord_sys + ")\nUse UTM84(33) or another specific coordinate system...");
//        startTransform(cString, lDetail, lOverview, lTransform, false);
    }
    else
    {
      ext = this.user2Device(this.m_extent_user);
    }

    var pts = ext.split(" ");
    var ll  = pts[0].split(",");
    var ur  = pts[1].split(",");
    var llx = parseFloat(ll[0]);
    var lly = parseFloat(ll[1]);
    var urx = parseFloat(ur[0]);
    var ury = parseFloat(ur[1]);

    var w = urx - llx;
    var h = lly - ury;  // Origo in upper left corner...
    gtSetWidth      (this.m_marker, Math.round(w + 0.5) + 4);
    gtSetHeight     (this.m_marker, Math.round(h + 0.5) + 4);
    gtSetLeft       (this.m_marker, Math.floor(llx) - 2);
    gtSetTop        (this.m_marker, Math.floor(ury) - 2);
    gtSetVisibility (this.m_marker, "visible");
  }; // end showMarker()



  // --------------------------------------------------------------------------
  //    Event handling
  // --------------------------------------------------------------------------
  m.raiseDrawStateChanged = function(state)
  {
    switch (state)
    {
      case "idle":
      if (this.m_tool != null)
        this.m_tool.update();
      break;
    }

    if (this.onDrawStateChanged)
      this.onDrawStateChanged.raise(state, this.m_url, this.m_viewport_user);
  }; // end raiseDrawStateChanged()



  // --------------------------------------------------------------------------
  //    Object database handling
  // --------------------------------------------------------------------------
  m.loadObjects = function gtMapJS_loadObjects(ids)
  {
    if (typeof(this.m_coord_sys) == "undefined")
      return;

//    top.gtTrace("gtMapJS::loadObjects()\n");
    if (!ids || ids === "")
      ids = this.m_default_ids;

    if (ids.length > 1)
    {
      if (ids.substring(0, 1) == "(")
        ids = ids.substring(1);
      if (ids.substring(ids.length - 1) == ")")
        ids = ids.substring(0, ids.length - 1);
    }

    var t_url = new gtUrl(this.m_url.toString());
    t_url.setParam("ids", "(" + ids + ")");
    t_url.setParam("dst", this.m_coord_sys);
    t_url.setParam("f", "xml");
    t_url.setParam("obj_min", this.m_url.getParam("s"));

    if (this.m_alt_obj_themes !== null)
      t_url.setParam("obj_themes", this.m_alt_obj_themes); // Use different themes when loading objects

    t_url.setService("LoadObjects");
    var prefix = window.location.protocol + "//" + window.location.hostname + "/GeoServe%3A";
    var ajax = new gtAjax(prefix + t_url.toString(), this.handleObjectsLoaded, this);
  }; // end loadObjects()



  m.handleObjectsLoaded = function gtMapJS_handleObjectsLoaded(ajax, dom, text)
  {
//    top.gtTrace("gtMapJS::handleObjectsLoaded()\n");
    this.m_objects_dom  = dom;
    this.m_objects_text = text;
    this.onObjectsLoaded.raise(this);
  }; // end handleObjectsLoaded()


  // Return named attribute's value (ignoring data type...)
  m.getFreeAttribute = function gtMapJS_getFreeAttribute(node, name)
  {
    var attr = node.firstChild;
    while (attr)
    {
      if (attr.nodeType == 1 && attr.nodeName == "attr" && attr.getAttribute("name") == name)
      {
        var val = attr.firstChild ? attr.firstChild.nodeValue : null;
//gtTraceLine("Attribute " + name + " = " + val);
        return val;
      }
      attr = attr.nextSibling;
    }
    return null;
  }; // end getFreeAttribute()
  

  m.saveXML = function gtMapJS_saveXML(xml)
  {
    if (typeof(this.m_coord_sys) == "undefined")
      return;

    var t_url = new gtUrl();
    t_url.setParam("src", this.m_coord_sys);
    t_url.setParam("f", "xml");
    t_url.setParam("user", this.m_url.getParam("user"));
    t_url.setParam("dst",  this.m_coord_sys);

    t_url.setService("ImportObjects");
    var prefix = window.location.protocol + "//" + window.location.hostname + "/GeoServe%3A";
    var ajax = new gtAjax(prefix + t_url.toString(), this.handleObjectsSaved, this, null, xml, "text/xml");
  }; // end saveXML()



  m.handleObjectsSaved = function gtMapJS_handleObjectsSaved(ajax, dom, text)
  {
//    top.gtTrace("gtMapJS::handleObjectsLoaded()\n");
    this.m_objects_dom  = dom;
    this.m_objects_text = text;
    this.onObjectsSaved.raise(this);
  }; // end handleObjectsSaved()


} // end gtBeMapJS()

