/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2008, 2009, 2010 Alexis Megas,
** 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://sf.net/projects/dooble
**   http://dooble.sf.net
****************************************************************************/

#include <QDir>
#include <QDateTime>
#include <QSettings>
#include <QSqlQuery>
#include <QSqlDatabase>

#include "dooble.h"
#include "ddownloadwindow.h"

ddownloadwindow::ddownloadwindow(void):QMainWindow()
{
  m_lastItemClicked = 0;
  ui.setupUi(this);
#ifdef Q_WS_MAC
  setAttribute(Qt::WA_MacMetalStyle, true);
#endif
  connect(ui.closePushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClose(void)));
  connect(ui.clearListPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClearList(void)));
  connect(ui.enterUrlPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotEnterUrl(void)));
  connect(ui.cancelPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotCancelDownloadUrl(void)));
  connect(ui.downloadPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotDownloadUrl(void)));
  connect(ui.clearPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClear(void)));
  slotSetIcons();
  populate();
}

ddownloadwindow::~ddownloadwindow()
{
  saveState();

  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       false).toBool())
    QFile::remove(QDir::homePath() + QDir::separator() +
		  ".dooble" + QDir::separator() + "downloads.db");
}

void ddownloadwindow::populate(void)
{
  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(QDir::homePath() + QDir::separator() +
		       ".dooble" + QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	if(query.exec("SELECT filename, path, url FROM downloads "
		      "ORDER BY sortby ASC"))
	  while(query.next())
	    {
	      QUrl url(QUrl::fromUserInput(query.value(2).toString()));

	      if(QFileInfo(url.toLocalFile()).exists())
		addFileItem(url.toLocalFile(),
			    query.value(1).toString() + QDir::separator() +
			    query.value(0).toString(),
			    false);
	      else if(url.isValid())
		addUrlItem(url,
			   query.value(1).toString() + QDir::separator() +
			   query.value(0).toString(),
			   false);
	    }
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::addFileItem(const QString &srcFileName,
				  const QString &dstFileName,
				  const bool isNew)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem();

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(itemClicked(void)),
	  this,
	  SLOT(slotItemClicked(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QString &,
				const QUrl &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QString &,
				  const QUrl &)));
  item->downloadFile(srcFileName, dstFileName, isNew);
  static_cast<QVBoxLayout *> (ui.frame->layout())->insertWidget(0, item);
}

void ddownloadwindow::addFileItem(QNetworkReply *reply,
				  const QString &dstFileName)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem();

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(itemClicked(void)),
	  this,
	  SLOT(slotItemClicked(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QString &,
				const QUrl &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QString &,
				  const QUrl &)));
  item->downloadFile(reply, dstFileName);
  static_cast<QVBoxLayout *> (ui.frame->layout())->insertWidget(0, item);
}

void ddownloadwindow::addUrlItem(const QUrl &url, const QString &fileName,
				 const bool isNew)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem();

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(itemClicked(void)),
	  this,
	  SLOT(slotItemClicked(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QString &,
				const QUrl &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QString &,
				  const QUrl &)));
  item->downloadUrl(url, fileName, isNew);
  static_cast<QVBoxLayout *> (ui.frame->layout())->insertWidget(0, item);
}

void ddownloadwindow::addHtmlItem(const QString &html,
				  const QString &dstFileName)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem();

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(itemClicked(void)),
	  this,
	  SLOT(slotItemClicked(void)));
  item->downloadHtml(html, dstFileName);
  static_cast<QVBoxLayout *> (ui.frame->layout())->insertWidget(0, item);
}

void ddownloadwindow::slotClose(void)
{
  close();
}

void ddownloadwindow::closeEvent(QCloseEvent *event)
{
  saveState();
  QMainWindow::closeEvent(event);
}

void ddownloadwindow::show(void)
{
  if(!isVisible())
   {
     /*
     ** Don't annoy the user.
     */

     if(dooble::s_settings.contains("downloadWindow/geometry"))
       setGeometry(dooble::s_settings.value("downloadWindow/geometry",
					    "").toRect());
   }

  QMainWindow::showNormal();
  raise();

  if(ui.stackedWidget->currentIndex() == 1)
    ui.urlLineEdit->setFocus();
  else
    ui.closePushButton->setFocus();
}

void ddownloadwindow::slotClearList(void)
{
  QList<ddownloadwindowitem *> items =
    findChildren<ddownloadwindowitem *> ();

  ddownloadwindowitem *item = 0;

  foreach(item, items)
    {
      if(!item->isDownloading())
	{
	  static_cast<QVBoxLayout *> (ui.frame->layout())->removeWidget(item);
	  item->deleteLater();
	}
    }

  QFile::remove(QDir::homePath() + QDir::separator() +
		".dooble" + QDir::separator() + "downloads.db");
}

void ddownloadwindow::slotEnterUrl(void)
{
  ui.stackedWidget->setCurrentIndex(1);
  ui.urlLineEdit->setFocus();
}

void ddownloadwindow::slotCancelDownloadUrl(void)
{
  ui.stackedWidget->setCurrentIndex(0);
}

void ddownloadwindow::slotDownloadUrl(void)
{
  QUrl url(QUrl::fromUserInput(ui.urlLineEdit->text().trimmed()));

  if(url.isValid())
    emit saveUrl(url);
}

void ddownloadwindow::slotSetIcons(void)
{
  QSettings settings
    (dooble::s_settings.value("iconSet").toString(), QSettings::IniFormat);

  setWindowIcon
    (QIcon(settings.value("downloadWindow/windowIcon").toString()));
  ui.closePushButton->setIcon
    (QIcon(settings.value("cancelButtonIcon").toString()));
  ui.cancelPushButton->setIcon
    (QIcon(settings.value("cancelButtonIcon").toString()));
  ui.clearPushButton->setIcon
    (QIcon(settings.value("downloadWindow/clearListButtonIcon").toString()));
  ui.clearListPushButton->setIcon
    (QIcon(settings.value("downloadWindow/clearListButtonIcon").toString()));
  ui.downloadPushButton->setIcon
    (QIcon(settings.value("downloadWindow/downloadButtonIcon").toString()));
  ui.enterUrlPushButton->setIcon
    (QIcon(settings.value("downloadWindow/enterUrlButtonIcon").
	   toString()));
  emit iconsChanged();
}

void ddownloadwindow::slotClear(void)
{
  ui.urlLineEdit->clear();
  ui.urlLineEdit->setFocus();
}

void ddownloadwindow::createDownloadDatabase(void)
{
  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       false).toBool())
    return;

  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(QDir::homePath() + QDir::separator() +
		       ".dooble" + QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	query.exec("CREATE TABLE IF NOT EXISTS downloads ("
		   "filename TEXT NOT NULL, "
		   "path TEXT NOT NULL, "
		   "url TEXT PRIMARY KEY NOT NULL, "
		   "sortby INTEGER NOT NULL)");
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::slotRecordDownload(const QString &fileName,
					 const QString &path,
					 const QUrl &url)
{
  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       false).toBool())
    return;

  createDownloadDatabase();

  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(QDir::homePath() + QDir::separator() +
		       ".dooble" + QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	query.prepare
	  ("INSERT OR REPLACE INTO downloads "
	   "(filename, path, url, sortby) "
	   "VALUES (?, ?, ?, ?)");
	query.bindValue(0, fileName);
	query.bindValue(1, path);
	query.bindValue(2, url.toString(QUrl::StripTrailingSlash));
	query.bindValue(3, QDateTime::currentMSecsSinceEpoch());
	query.exec();
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::saveState(void)
{
  /*
  ** geometry() may return (0, 0) coordinates if the window is
  ** not visible.
  */

  if(!isVisible())
    return;

  dooble::s_settings["downloadWindow/geometry"] = geometry();

  QSettings settings;

  settings.setValue("downloadWindow/geometry", geometry());
}

void ddownloadwindow::slotItemClicked(void)
{
  ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
    (sender());

  if(item)
    {
      if(m_lastItemClicked)
	m_lastItemClicked->setStyleSheet("background-color: white "
					 "}");

      item->setStyleSheet("background-color: lightgray "
			  "}");

      if(item != m_lastItemClicked)
	m_lastItemClicked = item;
    }
}
