/**
 *    Copyright 2006 - 2011 Opera Software ASA
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 *
 **/


window.cls || (window.cls = {});
cls.EcmascriptDebugger || (cls.EcmascriptDebugger = {});
cls.EcmascriptDebugger["6.0"] || (cls.EcmascriptDebugger["6.0"] = {});

/**
 * @fileoverview
  runtime_onload_handler is a workaround because some apis do not
  take into account if the document has finished loading
  like e.g the api to get the stylesheets.
  */

/**
  * @constructor
  */

window.cls.RuntimeOnloadHandler = function()
{
  // this is a workaround because some apis do not
  // take into account if the document has finished loading
  // like e.g the api to get the stylesheets

  const
  COMPLETE = 'complete';

  var
  __rts = {},
  __onload_handlers = {},
  poll_interval = 50;

  var reset_state_handler = function()
  {
    __rts = {};
    __onload_handlers = {};
  }

  var poll = function(rt_id)
  {
    if( blocked_rts[rt_id] )
    {
      setTimeout(poll, poll_interval, rt_id);
    }
    else
    {
      var tag = tagManager.set_callback(null, handleReadyState, [rt_id]);
      var script = "return document.readyState";
      services['ecmascript-debugger'].requestEval(tag, [rt_id, 0, 0, script]);
    }
  }

  var handleReadyState = function(status, message, rt_id)
  {
    const STATUS = 0, VALUE = 2;
    if( message[STATUS] == 'completed' )
    {
      if( message[VALUE] == COMPLETE)
      {
        __rts[rt_id] = COMPLETE;
        var onload_handlers = __onload_handlers[rt_id],  cur = null, i = 0;
        for( ; cur = onload_handlers[i]; i++)
        {
          // the call back must be hardcoded, without any this refernce
          cur.callee.apply(null, cur);
        }
        delete __onload_handlers[rt_id];
      }
      else
      {
        setTimeout(poll, poll_interval, rt_id);
      }
    }
    else
    {
      opera.postError(ui_strings.S_DRAGONFLY_INFO_MESSAGE +
        'getting readyState has failed in runtime_onload_handler handleReadyState');
    }
  }

  var register = function(rt_id, org_args)
  {
    if( !__onload_handlers[rt_id] )
    {
      __onload_handlers[rt_id] = [];
      poll(rt_id);
    }
    var onload_handlers = __onload_handlers[rt_id],  cur = null, i = 0;
    // if there the callback already exists, it will be replaced
    for( ; ( cur = onload_handlers[i] ) && cur.callee != org_args.callee ; i++);
    onload_handlers[i] = org_args;

  }

  this.check = function(rt_id, org_args)
  {
    // org_args is an arguments object
    // org_args.callee is the callback
    if( __rts[rt_id] == COMPLETE )
    {
      return true;
    }
    else
    {
      register(rt_id, org_args);
      return false;
    }
  }

  var blocked_rts = {};

  var onThreadStopped = function(msg)
  {
    blocked_rts[msg.stop_at.runtime_id] = true;
  }

  var onThreadContinue = function(msg)
  {
    blocked_rts[msg.stop_at.runtime_id] = false;
  }

  messages.addListener("thread-stopped-event", onThreadStopped);
  messages.addListener("thread-continue-event", onThreadContinue);
  messages.addListener('reset-state', reset_state_handler);

}

window.cls.EcmascriptDebugger["6.0"].RuntimeOnloadHandler = function()
{
  // this is a workaround because some apis do not
  // take into account if the document has finished loading
  // like e.g the api to get the stylesheets

  const
  COMPLETE = 'complete',
  RUNTIME_ID = 0,
  STATE = 1,
  DOM_CONTENT_LOADED = 1,
  LOAD = 2;

  var
  __rts = {},
  __onload_handlers = {},
  __rts_checked = {},
  poll_interval = 50;

  var reset_state_handler = function()
  {
    __rts = {};
    __onload_handlers = {};
    __rts_checked = {};
  }

  var poll = function(rt_id)
  {
    if( blocked_rts[rt_id] )
    {
      setTimeout(poll, poll_interval, rt_id);
    }
    else
    {
      var tag = tagManager.set_callback(null, handleReadyState, [rt_id]);
      var script = "return document.readyState";
      services['ecmascript-debugger'].requestEval(tag, [rt_id, 0, 0, script]);
    }
  }

  var call_callbacks = function(rt_id)
  {
    var onload_handlers = __onload_handlers[rt_id], cur = null, i = 0;
    if (onload_handlers)
    {
      for (; cur = onload_handlers[i]; i++)
      {
        // the call back must be hardcoded, without any this refernce
        cur.callee.apply(null, cur);
      }
    }
    __onload_handlers[rt_id] = null;
  }

  var handleReadyState = function(status, message, rt_id)
  {
    const STATUS = 0, VALUE = 2;
    if (message[STATUS] == 'completed')
    {
      __rts_checked[rt_id] = true;
      if (message[VALUE] == COMPLETE)
      {
        __rts[rt_id] = COMPLETE;
        call_callbacks(rt_id);
      }
    }
    else
    {
      opera.postError(ui_strings.S_DRAGONFLY_INFO_MESSAGE +
        'getting readyState has failed in runtime_onload_handler handleReadyState');
    }
  }

  var register = function(rt_id, org_args)
  {
    if (!__onload_handlers[rt_id])
    {
      __onload_handlers[rt_id] = [];
      if (!__rts_checked[rt_id])
        poll(rt_id);
    }
    var onload_handlers = __onload_handlers[rt_id], cur = null, i = 0;
    // if the callback already exists, it will be replaced
    for (; (cur = onload_handlers[i]) && cur.callee != org_args.callee; i++);
    onload_handlers[i] = org_args;
  }

  this.check = function(rt_id, org_args)
  {
    // org_args is an arguments object
    // org_args.callee is the callback
    if (__rts[rt_id] == COMPLETE)
    {
      return true;
    }
    else
    {
      register(rt_id, org_args);
      return false;
    }
  }

  var blocked_rts = {};

  var onThreadStopped = function(msg)
  {
    blocked_rts[msg.stop_at.runtime_id] = true;
  }

  var onThreadContinue = function(msg)
  {
    blocked_rts[msg.stop_at.runtime_id] = false;
  }

  this._onloadhandler = function(message)
  {
    var rt_id = message[RUNTIME_ID];
    __rts_checked[rt_id] = true;
    if (message[STATE] == LOAD)
    {
      __rts[rt_id] = COMPLETE;
      if (__onload_handlers[rt_id])
        call_callbacks(rt_id);
    }
  }

  messages.addListener("thread-stopped-event", onThreadStopped);
  messages.addListener("thread-continue-event", onThreadContinue);
  messages.addListener('reset-state', reset_state_handler);
  window.services['ecmascript-debugger'].addListener('readystatechanged', this._onloadhandler.bind(this));

}