function createElem(opt_className, opt_html, opt_tagName) {
  var tag = opt_tagName||"div";
  var elem = document.createElement(tag);
  if (opt_html) elem.innerHTML = opt_html;
  if (opt_className) elem.className = opt_className;
  return elem;
}



function SideBar(block_element, opt_options){
  var opts = opt_options||{};
  this.division = createElem("sidebar-contents");
  block_element.appendChild(this.division);
  this.show =  function(){this.division.style.display = "block"};
  this.hide =  function(){this.division.style.display = "none"};
  this.cats = [];

  this.addEntry = function(point,opt_options){
    var opts = opt_options||{};
    var iLabel = opts.iLabel||2;
    var label = createElem("sidebar-entry", point.textArray[iLabel], "a");
    label.href = "#";
    label.style.display = "block";
    label.onclick = function(){GEvent.trigger(point.marker,'click'); return false};//x-browser
    label.onfocus = function(){GEvent.trigger(point.marker,'click'); return false};
    
    this.division.appendChild(label);
    GEvent.addListener(point.marker,'click',function(){label.focus(); return false});
  }
  this.clear = function(){
    while (this.division.firstChild) {
      this.division.removeChild(this.division.firstChild);
    }
  }
}

/**
 * category to a sidebar
 * @author Esa 2008
 */ 
function BarCategory(sideBar, catName, opt_options){
  var me = this;
  var opts = opt_options||{};
  me.division = createElem("sidebar-cat");
  var cssClasses = "sidebar-cat-header cat-header-"+catName;
  var cat = createElem(cssClasses);
  me.markers = [];

  me.addEntry = function(point,opt_options){
    var opts = opt_options||{};
    me.markers.push(point.marker);
    var iLabel = opts.iLabel||2;
    var label = createElem("sidebar-entry", point.textArray[iLabel], "a");
    label.href = "#";
    label.style.display = "block";
    label.onclick = function(){GEvent.trigger(point.marker,'click'); return false};//x-browser
    label.onfocus = function(){GEvent.trigger(point.marker,'click'); return false};
    me.division.appendChild(label);
    GEvent.addListener(point.marker,'click',function(){label.focus(); return false});
  }
}




/**
 * Marker icon
 */
function tinyIcon(opt_color){
  var tiny = new GIcon();
  tiny.image = "img/gmap-pin.png";
  tiny.shadow = "img/gmap-shadow.png";
  tiny.iconSize = new GSize(20, 34);
  tiny.shadowSize = new GSize(37, 34);
  tiny.iconAnchor = new GPoint(9, 34);
  tiny.infoWindowAnchor = new GPoint(9, 2);
  return tiny;
}


/**
 * GMap2.showBounds() method. Fit bounds to viewport with paddings.
 * @ author Esa 2008
 * @ param bounds_ GLatLngBounds()
 * @ param opt_options Optional options object {top, right, bottom, left, save}
 */
GMap2.prototype.showBounds = function(bounds_, opt_options){
  var opts = opt_options||{};
  opts.top = opt_options.top*1||0;
  opts.left = opt_options.left*1||0;
  opts.bottom = opt_options.bottom*1||0;
  opts.right = opt_options.right*1||0;
  opts.save = opt_options.save||true;
  opts.disableSetCenter = opt_options.disableSetCenter||false;
  var ty = this.getCurrentMapType();
  var port = this.getSize();
  if(!opts.disableSetCenter){
    var virtualPort = new GSize(port.width - opts.left - opts.right, 
                            port.height - opts.top - opts.bottom);
    this.setZoom(ty.getBoundsZoomLevel(bounds_, virtualPort));
    var xOffs = (opts.left - opts.right)/2;
    var yOffs = (opts.top - opts.bottom)/2;
    var bPxCenter = this.fromLatLngToDivPixel(bounds_.getCenter());
    var newCenter = this.fromDivPixelToLatLng(new GPoint(bPxCenter.x-xOffs, bPxCenter.y-yOffs));
    this.setCenter(newCenter);
    if(opts.save)this.savePosition();
  }
  var portBounds = new GLatLngBounds();
  portBounds.extend(this.fromContainerPixelToLatLng(new GPoint(opts.left, port.height-opts.bottom)));
  portBounds.extend(this.fromContainerPixelToLatLng(new GPoint(port.width-opts.right, opts.top)));
  return portBounds;
}


/**
 * Map
 */
_mPreferMetric=true;                                 //to make size sure for IE too
var map = new GMap2(document.getElementById("map"), {size:new GSize(480,400)});
map.setCenter(new GLatLng(43.954208,-88.679558), 10);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());
map.enableScrollWheelZoom();
map.openInfoWindowHtml(map.getCenter(),"Nice to see you.");
map.closeInfoWindow(); //preloading infowindow


/**
 * parseCsv()
 * @return an array of GLatLng() objects
 * @param opt_options object {lat, lng} integers defining the csv cells of coordinates (default: {lat:1, lng:0})
 * @author Esa 2008
 */
String.prototype.parseCsv = function(opt_options){
  var results = [];
  var opts = opt_options||{};
  var iLat = opts.lat||1;
  var iLng = opts.lng||0;
  var lines = this.split("\n");
  for (var i=0; i<lines.length; i++) {
    var blocks = lines[i].split('"');
    //finding commas inside quotes. Replace them with '::::'
    for(var j=0;j<blocks.length;j++){
      if(j%2){
        blocks[j]=blocks[j].replace(/,/g,'::::');
      }
    }  //@author Esa 2008, keep this note.
    lines[i] = blocks.join("");
    var lineArray = lines[i].split(",");
    var lat = parseFloat(lineArray[iLat]);
    var lng = parseFloat(lineArray[iLng]);
    var point = new GLatLng(lat,lng);
    //after splitting by commas, we put hidden ones back
    for(var cell in lineArray){
      lineArray[cell] = lineArray[cell].replace(/::::/g,',');
    } //corrupted line step-over
    if(!isNaN(lat+lng)){
      point.textArray = lineArray;
      results.push(point);
    }
  }
  return results;
}




/**
 * Create the markers, with  infowindow.
 * Create sidebar categories and entries.
 */

var bounds = new GLatLngBounds();

GMap2.prototype.populate = function(points, options){
  var opts = options||{};

  var noCat = true;
  if(opts.cat||opts.iCat) noCat = false;
  var catName = opts.cat||"";
  var bar = opts.sidebar;
  var myCat;
  var newCats = [];
  for (var i=0; i < points.length; i++) {
    if(opts.iCat){ // category from file contents
      catName = points[i].textArray[opts.iCat];
    }
    var theIcon = opts.icon||CAT_ICONS[catName]||CAT_ICONS["DEFAULT_ICON"];
//    if(!bar.cats[catName]&&!noCat){ // create a category if not found
//      myCat = new BarCategory(bar, catName, {icon:theIcon});
//      newCats.push(myCat);
//    }
    var iLabel = opts.iLabel||2;
    var label = points[i].textArray[iLabel];
    points[i].marker = new GMarker(points[i],{title:label, icon:theIcon});
    this.addOverlay(points[i].marker);
    bounds.extend(points[i]); // this must be considered
    createInfoWindow(points[i],opts);
    if(noCat){
      bar.addEntry(points[i],opts);
    }else{
//      myCat.addEntry(points[i],opts);
      bar.addEntry(points[i],opts);
    }
  }

  var paddings = {top:30, right:10, bottom:10, left:50};
  this.showBounds(bounds,paddings); 
}



/**
 * create infowindow
 */
function createInfoWindow(point, opt_options){
  var opts = opt_options||{};
  var start = opts.iLabel||2;
  var iwNode = createElem("info-window");
  var iwRows = [];
  for(var i=start; i<point.textArray.length; i++){
  var row = createElem("iw-cell-"+i, point.textArray[i]);
  iwRows.push(row);
  iwNode.appendChild(row);
  }
  iwRows[0].className += " iw-header";
  point.marker.bindInfoWindow(iwNode,{maxWidth:300});
}




/**
 * This function triggers the downloading and parsing of a selected text file
 * marker, sidebar and infowindow data is extracted from the file
 */

  
var myBar = new SideBar(document.getElementById("sidebar"));

function ajaxLoad(textFile,opt_options){
  var opts = opt_options||{};
  opts.sidebar = myBar;
  var process = function(material){
    var entries = material.parseCsv(material, opts);
    map.populate(entries, opts);
  }
  GDownloadUrl(textFile, process);
}



var CAT_ICONS = [];
CAT_ICONS["DEFAULT_ICON"] = tinyIcon("blue");
CAT_ICONS["Stores"] = tinyIcon("blue");



window.onload = function(){
  ajaxLoad("stores.txt",{iCat:2, checked:true, iLabel:3});
}
