function run_request(type, url, data, callback)
{
              
  var req = new XMLHttpRequest();
  
  req.onreadystatechange = function()
  {
    if (req.readyState == 4 || req.readyState == 'complete' )
    {
        var t = req.responseText;
        if (t.length){
            var results = eval("(" + t + ")");        
        }
        callback( results );
    }
  };
  //req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 // req.setRequestHeader("Content-length", data.length);
  //req.setRequestHeader("Connection", "close");

  req.open(type,url,true);
  req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8");
  req.send(data);
}

function POST(url, data, callback)
{
    run_request('POST', url, data, callback);
}

function GET(url, callback)
{
    run_request('GET', url, null, callback);
}

function make_datastring(vals)
{
    var items = [];
    for (var k in vals)
    {
        items.push( k + "=" + encodeURIComponent(vals[k]));
    }
    var datastring = items.join("&");
    return datastring;
}function Checkboxes(bxs)
{
  var boxes;
  var overflow;
  var total_count;
  
  this.show = function()
  {
    this.setprop("display", "inline");
  }
  
  this.hide = function()
  {
    this.setprop("display", "none");
  }
  
  this.setprop = function(k, v)
  {
    for (var i in this.boxes)
    {
      var box = this.boxes[i];
      if (box.style) { box.style[k] = v; }
    }
  }
  
  this.get_ids = function()
  {
    var ids = new Array();
    for (var i in this.boxes)
    {
      var box = this.cbox(i);
      if (box.checked)
      {
        var id = box.id.match(/checkbox_(\d+)/)[1];
        ids.push(id);
      }
    }
    return ids;
  }
  
  this.select_all = function()
  {
    for (var i in this.boxes){ this.cbox(i).checked = true; }
  }
  
  this.deselect_all = function()
  {
    for (var i in this.boxes) { this.cbox(i).checked = false;  }
    this.overflow = false;
  }
  
  this.set_overflow = function() { this.overflow = true; }
  this.clear_overflow = function() { this.overflow = false; }
  
  this.get_selected_count = function()
  {
    var count = 0;
    for (var i in this.boxes) { if (this.cbox(i).checked){ count++ } }
    if ((count == this.boxes.length) && this.overflow)
    {
      return this.total_count;
    } else {
     return count;
    }
  }
  
  this.cbox = function(x) { return this.boxes[x].firstChild.nextSibling }
  
  this.set_change_listener = function(cb)
  {
    for (var b in this.boxes)
    {
      var node = this.cbox(b);
      node.addEventListener("change", cb, true);
    }
  }
  
  this.boxes = bxs;
  this.overflow = false;
  this.total_count = 999;
  var self = this;
  this.set_change_listener(function(){ self.clear_overflow() });
}function EditBox(argdiv)
  {
    var div;
    var event_handlers;
    var confirm_mode = false;
    var selected_set = null;
   
    
    this.display_error = function(err)
    {
      window.clearTimeout(this.curr_timeout);
      var error = document.getElementById("edit_error");
      error.innerHTML = err;
     // error.style.display = "block";
      this.opacity('edit_error', 150, 1, 10);
    }
    
    this.clear_errors = function()
    {
      var error = document.getElementsById("edit_error");
      error.innerHTML = "";
     // error.style.display = "none";
    }
    
    this.change_opac = function(opacity, id) 
    { 
      var object = document.getElementById(id).style; 
      if (opacity > 100){ opacity = 100; }
      object.opacity = (opacity / 100); 
      object.filter = "alpha(opacity=" + opacity + ")";
    }
    
    this.opacity = function(id, start, inc, step) 
    { 
      //speed for each frame       
      var new_o = start - inc;
      this.change_opac(new_o, id);
      var cmd = "$ebx.opacity('" + id + "'," + new_o + "," + inc + ',' + step +  ")";
      this.curr_timeout = setTimeout(cmd,step); 
    }

    this.set_evhandler = function(name, cb)
    {
      this.event_handlers[name] = cb;
    }
    
    this.send_event = function(name)
    {
      if (this.event_handlers[name])
      {
        this.event_handlers[name](); 
      } else if (this.event_handlers["default"]) 
      { 
        this.event_handlers["default"](name)
      }
      return false;
    }
    
    this.set_selected_count = function(c)
    {
       var sel = document.getElementById("selected_count");
       var disp ;
       if (c == "0")
       {
        disp = "no bookmarks selected";
       } else if (c == "1")
       {
        disp = "1 bookmark selected";
       } else {
        disp = c + " bookmarks selected";
       }
       sel.innerHTML = disp;
    }
    
    this.show = function()
    {
      this.div.style.display = "block";
      this.div.style.visibility = "visible";
    }
    
    this.hide = function()
    {
      this.div.style.visibility = "hidden";
      this.div.style.display = "none";
    }
    
    this.hide_confirmation = function()
    {
      this.hide_elem("confirm");
    }
    
    this.display_confirmation = function(msg)
    {
      var confirm = document.getElementById("confirm_message");
      confirm.innerHTML = msg;
      this.show_elem("confirm");
    }
      
    this.show_elem = function(name)
    {
      var e = document.getElementById(name);
      e.style.display = "block";
      e.style.visibility = "visible";
    }
    
    this.hide_elem =function(name)
    {
      var e = document.getElementById(name);
      e.style.display = "none";
      e.style.visibility = "hidden";
    }
    
    this.tag_value = function()
    {
      return document.getElementById("bulk_tag").value;
    }
    
    this.div = argdiv;
    this.event_handlers = new Object();
    this.confirm_mode = false;
  }function EditController()
{
  var pending_action;
  var total_bookmarks;
  

  
  this.post = function(action,ids,tag)
  {
    var vals = new Object();
    if (ids == 'all')
    {
        vals['all'] = true;
    } else {
        vals['ids'] = ids.join(",");
    }
    vals['action_type'] = action;
    if (tag)  { vals['tag'] = tag;  }
    var args = make_datastring(vals);
    POST("/bulk/", args, function(){ window.location.reload(); });
  //  POST("/bulk/", args, function(){  });
  }
    
  
  this.catchall_handler = function(name)
  {
    self.pending_event = name;
   // console.log("got event " + name );
    var count = $chk.get_selected_count();
    if (count < 1)
    {
      $ebx.display_error("no bookmarks selected");
      return;
    }
    
    
    switch(name)
    {
      case "mark_read":
      case "mark_unread":
      case "mark_starred":
      case "mark_unstarred":
      case "mark_private":
      case "mark_public":
        var ids;
        if ($chk.overflow) { ids = 'all'; } else {ids = $chk.get_ids(); }
        this.post(name, ids);
        break;
      
      case "confirm":
        //console.log("confirming action " + this.pending_action);
        var ids;
        if ($chk.overflow)
        {
            ids = 'all';
        } else {
            ids = $chk.get_ids();
        }
        this.post(this.pending_action, ids, this.pending_tag);
        break;
        
      case "cancel":
        this.pending_action = null;
        $ebx.hide_confirmation();
        this.pending_tag = null;
        break;
       
      case "delete":
        //console.log("handling event " + name);
        this.pending_action = name;
        var count = $chk.get_selected_count();
        $ebx.display_confirmation("Permanently delete " + count + " bookmarks?", name)
        break;
      
      case "add_tag":
      case "remove_tag":
        // check that there is a tag entered
        var tag = $ebx.tag_value();
        //console.log("tag is " + tag);
        if ((tag == null) || tag.trim().length < 1 )
        {
          $ebx.display_error("please enter a tag");
          return;
        }
        var action = name == "add_tag" ? "add tag to " : "remove tag from ";
        var count = $chk.get_selected_count()
        var disp = count == 1 ? action +  " one item?": action + count + " items?";
        $ebx.display_confirmation(disp, name);
        this.pending_action = name;
        this.pending_tag = tag;
        break;
     }
   }
  
  
  this.update_counts = function()
  {
     var count = $chk.get_selected_count();
     $ebx.set_selected_count(count);
  }
  
  this.select_all = function()
  {
    $ebx.hide_confirmation();
    $chk.select_all();
    $chk.set_overflow();
    this.update_counts();
  }
  
  this.select_page = function()
  {
    $ebx.hide_confirmation();
    $chk.select_all();
    $chk.clear_overflow();
    this.update_counts();
  }
  
  this.select_none = function()
  {
    $ebx.hide_confirmation();
    $chk.clear_overflow();
    $chk.deselect_all();
    this.update_counts();
    //console.log("selected none");
  }

 this.toggle_edit = function()
  {
    var link = document.getElementById("bulk_edit");
    
    if (this.editmode == false)
    {
      this.update_counts();
      $chk.show();
      $ebx.show();
      link.style.background = "#aaa";
      link.style.color = "#fff";
      link.style.border = "1px solid #999";
      this.editmode =true;
    } else {
      $chk.hide();
      $chk.deselect_all();
      $ebx.hide();
      link.style.background = "#fff";
      link.style.color = "#bbb";
      link.style.border = "0px solid #999";
      this.editmode = false;
    }
  }
 
  this.confirm_mode = false;
  this.editmode = false;
}function cook(thing)
{
  if (thing)
  {
   thing = thing.replace(/</g, '&lt;');
   thing = thing.replace(/>/g, '&gt;');
  }
  return thing;
}

function EditForm()
{
  this.fieldNames;
  this.init = function()
  {
    this.form = document.getElementById("edit_bookmark_form");
    this.fieldNames = Array("title", "description", "tags", "id", "url", "private", "toread");
    this.hide();
    this.fields = {};
    for (var f in this.fieldNames)
    {
      key = this.fieldNames[f]
      this.fields[key] = find_by_class_name(this.form, key);
    }
  }
  
  this.check_enter = function (e)
  { //e is event object passed from function invocation
    var characterCode = e.keyCode;
    if(characterCode == 13)
    { 
     //alert("saving!");
     ef.save_handler();
     return false;
   } else {
    return true;
  }
 }
 
  this.clear = function()
  {
    for (var f in this.fieldNames)
    {
      key = this.fieldNames[f];
      this.setField(key,null);
    }
  }
  
  this.setField = function(n,t)
  { 
    if (this.fields[n] == null) { return; }
    if (this.fields[n].type == "checkbox")
    {
      this.fields[n].checked = (t==true);
    } else {
      if (typeof(t) == "object")
      {
        if (t != null) { t = t.join(" "); }
      }
      if (t == null) { t = '';}
      if (this.fields[n].type != 'textarea') { t = cook(t); }
      this.fields[n].value = t;
    }
  }
  
  this.get_values = function()
  {
    var obj = new Object();
    for (var i in this.fields)
    {
      var elem = this.fields[i];
      if (elem.type == "checkbox")
      {
        obj[i] = elem.checked;
      } else {
        obj[i] = elem.value;
      }
    }
    return obj;
  }
  
  
  this.hide = function() 
  {  
    this.form.style.visibility = "hidden";
    this.form.style.display = "none";
  }
  
  this.show = function()
  {
    this.form.style.visibility = 'visible';
    this.form.style.display = 'block';
  }
  
  this.setSaveHandler = function(cb)
  {
    this.save_handler = cb;
    var button = find_by_class_name(this.form, "submit");
    if (button.addEventListener)
    {
        button.addEventListener("click", cb, true);
    } else if (button.attachEvent){
        button.attachEvent("onclick", cb);
    }
  }
  
  this.setCancelHandler = function(cb)
  {
    var button = find_by_class_name(this.form, "reset");
    if (button.addEventListener)
    {
        button.addEventListener("click", cb, true);
    } else if (button.attachEvent){
        button.attachEvent("onclick", cb);
    }
  }
}
EditForm.prototype = new EditForm();




function getDisplayDiv(id)
{
  var div = document.getElementById(id);
  content = find_by_class_name(div, "display");
  return content;
}
function showDiv(id)
{
  content = getDisplayDiv(id);
  content.style.visibility = "visible";
  content.style.display = "block";
}

function hideDiv(id)
{
  content = getDisplayDiv(id);
  content.style.visibility = "hidden";
  content.style.display = "none";
}

function destroy(id)
{
  //var df = document.forms["delete_form"];
  //df.bookmark_id.value = id;
  //df.action_type.value = "destroy";
  vals = {};
  vals['action'] = 'delete';
  vals['bookmark_id'] = id;
  
  if (activeID == id){ activeID = null;}
  vals['token'] = document.getElementById("edit_token").value;
  POST('/edit/', make_datastring(vals), function(bak)
  {
    delete(bmarks[id]);
    remove_element(id);
  });
  return false;
}



function delete_bmark(id)
{
  show_delete_link(id);
}

function cancel(id)
{
  show_confirm_link(id);
}

function hide_edit_form()
{
  //alert("hiding");
  showDiv(activeID);
  ef.hide();
}

function save_edit_form()
{
  var vals = ef.get_values();
  var token = document.getElementById("edit_token").value;
  vals['token'] = token;
  vals['bookmark_id'] = vals['id'];
  vals['private'] = (vals['private'] ? 1 : 0);
  vals['toread'] = (vals['toread'] ? 1 : 0);
  var datastring = make_datastring(vals);

  POST('/edit/', datastring, function(bak)
    {
     // console.log(bak);
      var objo = bak['original'];
      var id = objo.id;
      bmarks[id] = objo;
      //console.log("got this far");
      //console.log(bak['html']);
      update_element(id, bak['html']);
      ef.hide()      
      showDiv(id);
    });
}


function grab_bmark(id, origin)
{
  var token = document.getElementById("edit_token").value;
  vals = new Object();
  vals['token'] = token;
  vals['bookmark_id'] = id;
  vals['action'] = 'grab';
  if (origin != null)
  {
    vals['origin'] = origin;
  }
  datastring = make_datastring(vals);
  POST('/edit/', datastring, function(bak)
    {
        var s = document.getElementById(id);
        //console.log("looking for " + id);
        var t = find_by_class_name(s, "edit_links");
        //console.log("found " + t);
        t.style.display = "none";
    });
}



function update_element(id, html)
{ 
    //console.log("id + " + id + " ; html=" +html);
   var old_div = document.getElementById(id);
   var new_div = document.createElement("div");
   new_div.innerHTML = html;
   var new_node = new_div.firstChild;
   old_div.parentNode.replaceChild(new_node, old_div);
}

function remove_element(id)
{
    var div = document.getElementById(id);
    div.parentNode.removeChild(div);
}

function show_delete_link(id)
{
  var div = document.getElementById(id);
  var ddiv = find_by_class_name(div,"delete_link");
  var confirm = find_by_class_name(ddiv, "confirm");
  var del = find_by_class_name(ddiv, "delete");
  del.style.visibility = "hidden";
  del.style.display = "none";
  confirm.style.visibility ="visible";
  confirm.style.display = "inline";
}


function find_by_class_name(div, name)
{
    if (div.hasChildNodes())
    {        
        var pattern = new RegExp('\\b' + name + '\\b');
        var kids = div.childNodes;
        for (var s=0;s<kids.length;s++)
        {
            var child = kids[s];
           
            if (child.hasChildNodes())
            {
                var res = find_by_class_name(child, name);
                if (res != null) { return res;}
            }
        
            if (child.className)
            {
                var n = child.className;
                if (n.search(pattern) > -1) { return child; }
            }
        }
    }
    return null;
}
function show_confirm_link(id)
{
  var div = document.getElementById(id);
  var ddiv = find_by_class_name(div, "delete_link");
  var confirm = find_by_class_name(ddiv, "confirm");
  var del = find_by_class_name(ddiv, "delete");
  del.style.visibility = "visible";
  del.style.display = "inline";
  confirm.style.visibility ="hidden";
  confirm.style.display ="none";
}


function edit(id)
{
  if (activeID)
  {
    showDiv(activeID);
  }
  var div = document.getElementById(id);
  activeID = id;
  ef.clear();
  div.insertBefore(ef.form,div.firstChild.nextSibling.nextSibling);
  b = bmarks[id];
  for (var f in ef.fieldNames)
  {
    var key = ef.fieldNames[f];
    //console.log(key);
    //alert(key);
    ef.setField(key, b[key]);
  }
  hideDiv(id);
  ef.show();

}

function mark_as_read(id)
{
  var token = document.getElementById("edit_token").value;
  var post_string = 'bookmark_id=' + id;
  post_string += '&action=mark_read';
  post_string += '&token=' + token;
  POST("/edit/", post_string, function()
  {
    bmarks[id].toread = false;
    remove_read_button(id);
  });
}

function remove_read_button(id)
{
  var div = document.getElementById(id);
  var button = find_by_class_name(div, "read");
  button.style.display = "none";
}
var SELECT_URL = "/ajax/select/";
var UNSELECT_URL = "/ajax/unselect/";
var busy = false;

function toggle_star(id)
{
  if (busy) { return; }
  
  busy = true;
  //console.log("getting star element " + id);
  var star = get_star_element(id);
  if (star.className.indexOf("selected_star") > -1 )
  {
    // unselect
    POST(UNSELECT_URL,  "id="+id , function(){ mark_unstarred(id);busy=false; } );
  } else {
    //select
    POST(SELECT_URL, "id="+id, function(){ mark_starred(id); busy=false;} );  
  }
}

function get_star_element(id)
{
  var parent = document.getElementById(id);
  if (parent != null)
  {
    return find_by_class_name(parent, "star");
  }
}



function mark_private(id)
{
  var div = document.getElementById(id);
  div.className = "bookmark private";
  bmarks[id].private = true;
}

function mark_public(id)
{
  var div = document.getElementById(id);
  div.className = "bookmark";
  bmarks[id].private = false;
}


function mark_starred(id) 
{
  var elem = get_star_element(id);
  try
  {
    elem.className = "star selected_star"; 
  } catch(e){}
}

function mark_unstarred(id)
{
  var elem = get_star_element(id);
  try {
   elem.className = "star";  
   } catch(e)
   { }
}


function add_tag(t)
{
    var field = document.getElementById('tags');
    var curr = field.value;
    var tag_regex = new RegExp( "\\b" + t + "\\b");
    if (curr.match(tag_regex) == null)
    {
        // TODO handle case when tag is at start of field
        field.value +=  " " + t;
    }
    return false;
}
    
    
  function apply_all(action)
  {
    var cb;
    var tag = null;
    
    switch(action)
    {
      case "set_starred":
        cb = mark_starred;
        break;
      
      case "set_unstarred":
        cb = mark_unstarred;
        break;
      
      case "make_public":
        cb = mark_public;
        break;
        
      case "make_private":
        cb = mark_private;
        cb = reload;
        break;
      
      case "set_read":
      case "set_unread":
        cb = reload;
        break;
        
      case "add_tag":
      case "strip_tag":
        tag = get_bulk_tag();
        cb = reload;
        break;
              
    }


    var idlist = Array();
    for (var b in bmarks)
    {
       var item = bmarks[b];
       idlist.push(item.id);
    }
    var idstring = idlist.join(",");
    var args = "ids=" +idlist + "&action_type=" + action;
    if (tag)
    {
      args += "&tag=" + tag;
    }
    POST("/bulk/", args, 
      function()
      {
        if (cb)
        {
          for (var b in bmarks)
          {
            cb(bmarks[b].id);
          }
        }
      }
      );
  }
  
  
function reload()
{
  window.location.reload();
}

function get_bulk_tag()
{
  var tag = document.getElementById("tag_name").value;
  return tag;
}
  
function mark_stars()
  {
    for (var i in starred)
    {
      var id = starred[i];
      mark_starred(id);
    }
  }
  
  
function subscribe(user_id, token)
{
  POST("/subscribe/", "username=" + user_id + "&token=" + token, 
    function()
    {  
      show("subscribed");
      hide("unsubscribed");
    });
}

function unsubscribe(user_id, token, reload)
{
  var re = re;
  POST("/unsubscribe/", "username=" + user_id + "&token=" + token, 
    function()
    { 
      show("unsubscribed");
      hide("subscribed");
      if (reload)
      {
        document.location = document.location;
      }
    });
}


function show(div)
{
  var elem = document.getElementById(div);
  if (elem != null)
  {
    elem.style.visibility = "visible";
    elem.style.display = "block";
  }
}

function hide(div)
{
  var elem = document.getElementById(div);
  if (elem != null)
  {
    elem.style.visibility = "hidden";
    elem.style.display = "none";
  
  }
}