var $, Backbone, Document, Promise, RootAddedEvent, RootRemovedEvent, TitleChangedEvent, _, _create_view, _get_session, _handle_notebook_comms, _init_comms, _render_document_to_element, _sessions, add_document_from_session, add_document_static, add_model_from_session, add_model_static, base, embed_items, fill_render_item_from_script_tag, inject_css, inject_raw_css, logger, pull_session, ref, ref1, set_log_level;

$ = require("jquery");

_ = require("underscore");

Backbone = require("backbone");

base = require("./base");

ref = require("./logging"), logger = ref.logger, set_log_level = ref.set_log_level;

ref1 = require("./document"), Document = ref1.Document, RootAddedEvent = ref1.RootAddedEvent, RootRemovedEvent = ref1.RootRemovedEvent, TitleChangedEvent = ref1.TitleChangedEvent;

pull_session = require("./client").pull_session;

Promise = require("es6-promise").Promise;

_handle_notebook_comms = function(msg) {
  var data;
  logger.debug("handling notebook comms");
  data = JSON.parse(msg.content.data);
  if ('events' in data && 'references' in data) {
    return this.apply_json_patch(data);
  } else if ('doc' in data) {
    return this.replace_with_json(data['doc']);
  } else {
    throw new Error("handling notebook comms message: ", msg);
  }
};

_init_comms = function(target, doc) {
  var comm_manager;
  if (typeof Jupyter !== "undefined" && Jupyter !== null) {
    comm_manager = Jupyter.notebook.kernel.comm_manager;
    return comm_manager.register_target(target, function(comm, msg) {
      logger.info("Registering Jupyter comms for target " + target);
      return comm.on_msg(_.bind(_handle_notebook_comms, doc));
    });
  } else {
    return console.warn('Juptyer notebooks comms not available. push_notebook will not function');
  }
};

_create_view = function(model) {
  var view;
  view = new model.default_view({
    model: model
  });
  base.index[model.id] = view;
  return view;
};

add_model_static = function(element, model_id, doc) {
  var model, view;
  model = doc.get_model_by_id(model_id);
  if (model == null) {
    throw new Error("Model " + model_id + " was not in document " + doc);
  }
  view = _create_view(model);
  return _.delay(function() {
    return $(element).replaceWith(view.$el);
  });
};

_render_document_to_element = function(element, document, use_for_title) {
  var i, len, model, ref2, render_model, unrender_model, views;
  views = {};
  render_model = function(model) {
    var view;
    view = _create_view(model);
    views[model.id] = view;
    return $(element).append(view.$el);
  };
  unrender_model = function(model) {
    var view;
    if (model.id in views) {
      view = views[model.id];
      $(element).remove(view.$el);
      delete views[model.id];
      return delete base.index[model.id];
    }
  };
  ref2 = document.roots();
  for (i = 0, len = ref2.length; i < len; i++) {
    model = ref2[i];
    render_model(model);
  }
  if (use_for_title) {
    window.document.title = document.title();
  }
  return document.on_change(function(event) {
    if (event instanceof RootAddedEvent) {
      return render_model(event.model);
    } else if (event instanceof RootRemovedEvent) {
      return unrender_model(event.model);
    } else if (use_for_title && event instanceof TitleChangedEvent) {
      return window.document.title = event.title;
    }
  });
};

add_document_static = function(element, doc, use_for_title) {
  return _.delay(function() {
    return _render_document_to_element($(element), doc, use_for_title);
  });
};

_sessions = {};

_get_session = function(websocket_url, session_id) {
  var subsessions;
  if ((websocket_url == null) || websocket_url === null) {
    throw new Error("Missing websocket_url");
  }
  if (!(websocket_url in _sessions)) {
    _sessions[websocket_url] = {};
  }
  subsessions = _sessions[websocket_url];
  if (!(session_id in subsessions)) {
    subsessions[session_id] = pull_session(websocket_url, session_id);
  }
  return subsessions[session_id];
};

add_document_from_session = function(element, websocket_url, session_id, use_for_title) {
  var promise;
  promise = _get_session(websocket_url, session_id);
  return promise.then(function(session) {
    return _render_document_to_element(element, session.document, use_for_title);
  }, function(error) {
    logger.error("Failed to load Bokeh session " + session_id + ": " + error);
    throw error;
  });
};

add_model_from_session = function(element, websocket_url, model_id, session_id) {
  var promise;
  promise = _get_session(websocket_url, session_id);
  return promise.then(function(session) {
    var model, view;
    model = session.document.get_model_by_id(model_id);
    if (model == null) {
      throw new Error("Did not find model " + model_id + " in session");
    }
    view = _create_view(model);
    return $(element).replaceWith(view.$el);
  }, function(error) {
    logger.error("Failed to load Bokeh session " + session_id + ": " + error);
    throw error;
  });
};

inject_css = function(url) {
  var link;
  link = $("<link href='" + url + "' rel='stylesheet' type='text/css'>");
  return $('body').append(link);
};

inject_raw_css = function(css) {
  var style;
  style = $("<style>").html(css);
  return $('body').append(style);
};

fill_render_item_from_script_tag = function(script, item) {
  var info;
  info = script.data();
  if ((info.bokehLogLevel != null) && info.bokehLogLevel.length > 0) {
    set_log_level(info.bokehLogLevel);
  }
  if ((info.bokehDocId != null) && info.bokehDocId.length > 0) {
    item['docid'] = info.bokehDocId;
  }
  if ((info.bokehModelId != null) && info.bokehModelId.length > 0) {
    item['modelid'] = info.bokehModelId;
  }
  if ((info.bokehSessionId != null) && info.bokehSessionId.length > 0) {
    item['sessionid'] = info.bokehSessionId;
  }
  return logger.info("Will inject Bokeh script tag with params " + (JSON.stringify(item)));
};

embed_items = function(docs_json, render_items, websocket_url) {
  var container, docid, docs, elem, element_id, i, item, len, promise, results, use_for_title;
  if (websocket_url == null) {
    websocket_url = null;
  }
  docs = {};
  for (docid in docs_json) {
    docs[docid] = Document.from_json(docs_json[docid]);
  }
  results = [];
  for (i = 0, len = render_items.length; i < len; i++) {
    item = render_items[i];
    if (item.notebook_comms_target != null) {
      _init_comms(item.notebook_comms_target, docs[docid]);
    }
    element_id = item['elementid'];
    elem = $('#' + element_id);
    if (elem.length === 0) {
      throw new Error("Error rendering Bokeh model: could not find tag with id: " + element_id);
    }
    if (elem.length > 1) {
      throw new Error("Error rendering Bokeh model: found too many tags with id: " + element_id);
    }
    if (!document.body.contains(elem[0])) {
      throw new Error("Error rendering Bokeh model: element with id '" + element_id + "' must be under <body>");
    }
    if (elem.prop("tagName") === "SCRIPT") {
      fill_render_item_from_script_tag(elem, item);
      container = $('<div>', {
        "class": 'bokeh-container'
      });
      elem.replaceWith(container);
      elem = container;
    }
    use_for_title = (item.use_for_title != null) && item.use_for_title;
    promise = null;
    if (item.modelid != null) {
      if (item.docid != null) {
        add_model_static(elem, item.modelid, docs[item.docid]);
      } else if (item.sessionid != null) {
        promise = add_model_from_session(elem, websocket_url, item.modelid, item.sessionid);
      } else {
        throw new Error("Error rendering Bokeh model " + item['modelid'] + " to element " + element_id + ": no document ID or session ID specified");
      }
    } else {
      if (item.docid != null) {
        add_document_static(elem, docs[item.docid], use_for_title);
      } else if (item.sessionid != null) {
        promise = add_document_from_session(elem, websocket_url, item.sessionid, use_for_title);
      } else {
        throw new Error("Error rendering Bokeh document to element " + element_id + ": no document ID or session ID specified");
      }
    }
    if (promise !== null) {
      results.push(promise.then(function(value) {
        return console.log("Bokeh items were rendered successfully");
      }, function(error) {
        return console.log("Error rendering Bokeh items ", error);
      }));
    } else {
      results.push(void 0);
    }
  }
  return results;
};

module.exports = {
  embed_items: embed_items,
  inject_css: inject_css,
  inject_raw_css: inject_raw_css
};
