/**

* TODO exceptions should exit immediately from phantomjs and they DON'T
* TODO support 404 and error code in the same way prerender.io (server) does
* @type {number}
*/

var EVALUATE_JAVASCRIPT_CHECK_TIMEOUT = 50;

var page = require(‘webpage’).create(),

system = require('system'),
URI = require('./URI'),
fs = require('fs');

var surrender = {}; page.viewportSize = {

width: 1024,
height: 800

};

surrender.params = function() {

if (system.args.length === 1) {
    throw 'Usage: prerender_rails_embedded.js <some URL>';
}
return { address: system.args[1]};

};

surrender.javascriptToExecuteOnPage = function() {

function removeTag(tagName) {
  var element = document.getElementsByTagName(tagName);
  for (var index = element.length - 1; index >= 0; index--) {
    element[index].parentNode.removeChild(element[index]);
  }
}

var processHtml = function() {
  removeTag('script');
  removeTag('iframe');

  if (!window.prerenderRailsEmbedded || !window.prerenderRailsEmbedded.filterHtmlOutput || typeof(window.prerenderRailsEmbedded.filterHtmlOutput) !== "function") {
    return document.documentElement.outerHTML;
  } else {
    return window.prerenderRailsEmbedded.filterHtmlOutput.call(this);
  }
};

try {

  if (!document) {
    throw 'document is undefined. this function must be called inside page.evaluate ';
  }
  var html = processHtml();
  var doctype = '';

  if(document && document.doctype) {
    doctype = "<!DOCTYPE "
      + document.doctype.name
      + (document.doctype.publicId ? ' PUBLIC "' + document.doctype.publicId + '"' : '')
      + (!document.doctype.publicId && document.doctype.systemId ? ' SYSTEM' : '')
      + (document.doctype.systemId ? ' "' + document.doctype.systemId + '"' : '')
      + '>';
  }

  return {
    html: doctype + html,
    shouldWaitForPrerenderReady: typeof window.prerenderReady === 'boolean',
    prerenderReady: window.prerenderReady
  };

} catch (e) {
  //console.log('ERROR: ', e);
  return  {
    html: '',
    shouldWaitForPrerenderReady: false,
    prerenderReady: window.prerenderReady
  };
}

};

surrender.millisElapsed = function () {

return new Date().getTime() - this.requestStarted.getTime();

};

surrender.serveHtml = function(html) {

system.stdout.writeLine(html);

this.logDebug('page returned to rails: ' + page.address + " (" + this.millisElapsed() + "ms)");
phantom.exit(0);

};

surrender.evaluateJavascriptOnPage = function(t, msPassed) {

var _this = t || this
    , out = page.evaluate(_this.javascriptToExecuteOnPage);

if (msPassed === undefined) msPassed = 0;

if(!out.shouldWaitForPrerenderReady || (out.shouldWaitForPrerenderReady && out.prerenderReady) || msPassed >= 20000) {

  if (msPassed >= 20000) _this.logWarning("prerenderReady=true not found after 20s for page: " + page.url);

  _this.serveHtml(out.html);

} else {
    _this.evaluateJavascriptTimeout = setTimeout(function(){_this.evaluateJavascriptOnPage(_this, msPassed + EVALUATE_JAVASCRIPT_CHECK_TIMEOUT)}, EVALUATE_JAVASCRIPT_CHECK_TIMEOUT);
}
return _this;

};

surrender.run = function() {

var _this = this;

try {

  page.address = this.replaceHostWithLocalhost(this.removeEscapedFragmentParameter(this.params().address));
  page.settings.userAgent = 'EtaliaBotAgent';
  page.settings.resourceTimeout = 15000;

  _this.logDebug('requested: ' + page.address);
  surrender.requestStarted = new Date();

  page.open(page.address, function (st) {
    _this.logDebug('opened: ' + page.address + 'with status: ' + st);

    if (st !== 'success') throw 'FAIL to load the address';

    _this.evaluateJavascriptOnPage();
  });

} catch(e) {
    _this.logError(e);
    console.log(e);
    phantom.exit(1);
}

page.onError = function(message, trace) {
  _this.logError(message);
};

page.onConsoleMessage = function(message, lineNum, sourceId) {
  _this.logInfo('CONSOLE: ' + message + '(' + sourceId + '/L#"' + lineNum + '")');
};

page.onResourceTimeout = function(request) {
  console.log('<html><head><meta name="robots" content="noindex, noarchive" /></head><body></body></html>');
  _this.logWarning('Response (#' + request.id + '): ' + JSON.stringify(request));
  setTimeout(function() { phantom.exit(1); }, 0); // workaround to avoid PhantomJS crashes
};

//page.onResourceRequested = function(requestData, networkRequest) {
//  _this.logWarning('-------- (#' + requestData.id + '): ' + requestData.url + ' ' + JSON.stringify(requestData.headers));
//};

}; surrender.removeEscapedFragmentParameter = function (addressUrl) {

var parts = new URI(addressUrl);

// Remove the _escaped_fragment_ query parameter
if (parts.hasSearch('_escaped_fragment_')) {
  if(parts.search(true)['_escaped_fragment_']) {
    parts.hash("#!" + parts.search(true)['_escaped_fragment_']);
  }
  parts.removeSearch('_escaped_fragment_');
}

var newUrl = parts.toString();
if(newUrl[0] === '/') newUrl = newUrl.substr(1);

return newUrl;

};

surrender.replaceHostWithLocalhost = function (addressUrl) {

this.logDebug(new URI(addressUrl).hostname('localhost'));
return new URI(addressUrl).hostname('localhost');

};

surrender.logFilePath = function() {

if (fs.exists("/opt/sites/frontend/current/log"))
  return "/opt/sites/frontend/current/log";
else
  return "/tmp";

}; surrender.flog = function(message) {

try {
  fs.write(this.logFilePath() + '/etalia-prerender.log', message + "\n", 'a');
} catch(e) {
  // can't fallback on anything
}

}; surrender.logDebug = function(message) {

this.flog(this.timestamp() + ' [DEBUG] ' + message);

}; surrender.logInfo = function(message) {

this.flog(this.timestamp() + ' [INFO ] ' + message);

}; surrender.logWarning = function(message) {

this.flog(this.timestamp() + ' [WARN ] ' + message);

}; surrender.logError = function(message) {

this.flog(this.timestamp() + ' [ERROR] ' + message);

};

surrender.timestamp = function() {

return new Date().toString().substring(0,24);

};

surrender.run();