/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2008, 2009, 2010 Ronald Landheer-Cieslak,
** Gunther van Dooble, and the Dooble Team. 
** All rights reserved.
**
** License: GPL2 only:
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; version 2 of the License only.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
** or see here: http://www.gnu.org/licenses/gpl.html
**
** For the WebKit library, please see: http://webkit.org.
**
** THE CODE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY
** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
** IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS APPLICATION, EVEN IF ADVISED
** OF THE POSSIBILITY OF SUCH DAMAGE.
**
** Please report all praise, requests, bugs, and problems to the project
** team and administrators: http://sf.net/projects/dooble.
**
** You can find us listed at our project page. New team members are welcome.
** The name of the authors should not be used to endorse or promote products
** derived from Dooble without specific prior written permission.
** If you use this code for other projects, please let us know.
**
** Web sites:
**   http://dooble.net/projects/dooble
**   http://dooble.sf.net
**   http://www.getadooble.com
****************************************************************************/

#include "dooble.h"
#include "dwebpage.h"

#include <QUrl>
#include <QFile>
#include <QSettings>
#include <QWebFrame>

dwebpage::dwebpage(QObject *parent /* = 0 */):QWebPage(parent),
					      never_show_error_page_(false),
					      never_emit_error_signal_(false)
{
  connect(this, SIGNAL(unsupportedContent(QNetworkReply *)),
	  this, SLOT(handleUnsupportedContent(QNetworkReply *)));
  setForwardUnsupportedContent(true);
}

void dwebpage::handleUnsupportedContent(QNetworkReply *reply)
{
  if(!reply) return; // Silent failure, if no reply.

  bool show_error_page(false);
  bool emit_error_signal(false);
  const char *title_string(0);
  const char *message_string(0);
  QUrl target_url(reply->url());
  QNetworkReply::NetworkError error(reply->error());

  switch (error)
    {
    case QNetworkReply::NoError: // No error condition.
      break;
    case QNetworkReply::ConnectionRefusedError: /*
						** The remote server
						** refused the connection
						** (the server is not
						** accepting requests).
						*/
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The remote server refused the connection "
	"(the server is not accepting requests).";
      break;
    case QNetworkReply::RemoteHostClosedError: /*
					       ** The remote server
					       ** closed the connection
					       ** prematurely, before the
					       ** entire reply was received
					       ** and processed.
					       */
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Server Error";
      message_string = "The remote server closed the connection "
	"prematurely, before the entire reply was received and processed.";
      break;
    case QNetworkReply::HostNotFoundError: /*
					   ** The remote host name was
					   ** not found (invalid hostname).
					   */
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The remote host name was not found "
	"(invalid hostname).";
      break;
    case QNetworkReply::TimeoutError :			// the connection to the remote server timed out
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The connection to the remote server timed out.";
      break;
    case QNetworkReply::OperationCanceledError :		// the operation was canceled via calls to abort() or close() before it was finished.
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The operation was canceled via calls to abort() or close() before it was finished.";
      break;
    case QNetworkReply::SslHandshakeFailedError :		// the SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted.
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The SSL/TLS handshake failed and the encrypted channel could not be established.";
      break;
    case QNetworkReply::ProxyConnectionRefusedError :	// the connection to the proxy server was refused (the proxy server is not accepting requests)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The connection to the proxy server was refused (the proxy server is not accepting requests).";
      break;
    case QNetworkReply::ProxyConnectionClosedError :	// the proxy server closed the connection prematurely, before the entire reply was received and processed
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Proxy Error";
      message_string = "The proxy server closed the connection prematurely, before the entire reply was received and processed.";
      break;
    case QNetworkReply::ProxyNotFoundError :		// the proxy host name was not found (invalid proxy hostname)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The proxy host name was not found (invalid proxy hostname).";
      break;
    case QNetworkReply::ProxyTimeoutError :			// the connection to the proxy timed out or the proxy did not reply in time to the request sent
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Proxy Error";
      message_string = "The connection to the proxy timed out or the proxy did not reply in time to the request sent.";
      break;
    case QNetworkReply::ProxyAuthenticationRequiredError :	// the proxy requires authentication in order to honor the request but did not accept any credentials offered (if any)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The proxy requires authentication in order to honor the request but did not accept any credentials offered (if any).";
      break;
    case QNetworkReply::ContentAccessDenied :		// the access to the remote content was denied (similar to HTTP error 401)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The access to the remote content was denied.";
      break;
    case QNetworkReply::ContentOperationNotPermittedError :	// the operation requested on the remote content is not permitted
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The operation requested on the remote content is not permitted.";
      break;
    case QNetworkReply::ContentNotFoundError :		// the remote content was not found at the server (similar to HTTP error 404)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The remote content was not found at the server.";
      break;
    case QNetworkReply::AuthenticationRequiredError :	// the remote server requires authentication to serve the content but the credentials provided were not accepted (if any)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Connection Error";
      message_string = "The remote server requires authentication to serve the content but the credentials provided were not accepted (if any).";
      break;
    case QNetworkReply::ProtocolUnknownError :		// the Network Access API cannot honor the request because the protocol is not known
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Protocol Unknown";
      message_string = "The Network Access API cannot honor the request because the protocol is not known.";
      break;
    case QNetworkReply::ProtocolInvalidOperationError :	// the requested operation is invalid for this protocol
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Protocol Error";
      message_string = "The requested operation is invalid for this protocol.";
      break;
    case QNetworkReply::UnknownNetworkError :		// an unknown network-related error was detected
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Unknown Network Error";
      message_string = "An unknown network-related error was detected.";
      break;
    case QNetworkReply::UnknownProxyError :			// an unknown proxy-related error was detected
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Unknown Proxy Error";
      message_string = "An unknown proxy-related error was detected.";
      break;
    case QNetworkReply::UnknownContentError :		// an unknown error related to the remote content was detected
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Unknwon Content Error";
      message_string = "An unknown error related to the remote content was detected.";
      break;
    case QNetworkReply::ProtocolFailure :			// a breakdown in protocol was detected (parsing error, invalid or unexpected responses, etc.)
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Protocol Failure";
      message_string = "A breakdown in protocol was detected (parsing error, invalid or unexpected responses, etc.).";
      break;
    default :						// unknown error
      show_error_page = true;
      emit_error_signal = true;
      title_string = "Unknown Error";
      message_string = "An unknown error occured.";
      break;
    }

  if(show_error_page && !never_show_error_page_)
    {
      QFile file(QLatin1String(":/NavigationError.html"));
      bool is_opened = file.open(QIODevice::ReadOnly);
      Q_UNUSED(is_opened);
      Q_ASSERT(is_opened);
      QString title = tr("Error loading page: %1").arg
	(target_url.toString(QUrl::StripTrailingSlash));
      QString html = QString(QLatin1String(file.readAll()))
	.arg(title_string)
	.arg(message_string)
	.arg(target_url.toString());
      QList<QWebFrame*> frames;
      frames.append(mainFrame());
      bool shown(false);

      while(!frames.isEmpty() && !shown)
	{
	  QWebFrame *frame = frames.takeFirst();

	  if(frame->url() == reply->url())
	    {
	      frame->setHtml(html, reply->url());
	      shown = true;
	    }
	  else
	    {
	      QList<QWebFrame *> children = frame->childFrames();

	      foreach(QWebFrame *frame, children)
		frames.append(frame);
	    }
	}

      if(!shown)
	mainFrame()->setHtml(html, reply->url());
      else
	{
	  /*
	  ** Already shown, or don't show here.
	  */
	}
    }
  else
    {
      /*
      ** Either not an error or don't show it.
      */
    }

  if(emit_error_signal && !never_emit_error_signal_)
    emit networkError(error);
  else
    {
      /*
      ** Don't emit any signals.
      */
    }
}

QWebPage *dwebpage::createWindow(WebWindowType type)
{
  Q_UNUSED(type);

  QSettings settings;

  if(!settings.value("settingsWindow/javascriptAllowNewWindows",
		     false).toBool())
    return 0;

  if(settings.value("settingsWindow/openInNewTab", true).toBool())
    {
      dview *new_page = findDooble()->newTab(tr("about: blank"));

      Q_ASSERT(new_page);
      new_page->clearHistoryAfterNextLoad();
      return new_page->page();
    }
  else
    {
      dview *v = 0;
      dooble *dbl = new dooble();

      v = dbl->newTab(tr("about: blank"));
      v->clearHistoryAfterNextLoad();
      return v->page();
    }
}

dooble *dwebpage::findDooble(void)
{
  dooble *dbl(0);
  QObject *prnt(this);

  do
    {
      prnt = prnt->parent();
      dbl = dynamic_cast<dooble *> (prnt);
    }
  while (prnt != 0 && dbl == 0);

  return dbl;
}

QString dwebpage::userAgentForUrl(const QUrl &url) const
{
  Q_UNUSED(url);

  QString str("");

  str = QString("%1/%2 (%3) WebKit").
    arg(QCoreApplication::applicationName()).
    arg(QCoreApplication::applicationVersion()).
    arg(QLocale::system().name());

  return str;
}

dwebpage::~dwebpage()
{
}
