/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2011, 2012 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 <QBuffer>
#include <QDateTime>
#include <QSqlQuery>
#include <QSqlDatabase>

#include "dmisc.h"
#include "dooble.h"
#include "dfilesystemmodel.h"

dfilesystemmodel::dfilesystemmodel(QObject *parent):QFileSystemModel(parent)
{
  m_headers << tr("Name")
	    << tr("Size")
	    << tr("Type")
	    << tr("Date Modified")
	    << tr("Date Accessed")
	    << tr("Owner")
	    << tr("Group")
	    << tr("Permissions");
  connect(this,
	  SIGNAL(directoryLoaded(const QString &)),
	  this,
	  SLOT(slotDirectoryLoaded(const QString &)));
}

QVariant dfilesystemmodel::headerData(int section, Qt::Orientation orientation,
				      int role) const
{
  if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
      if(section >= 0 && section < m_headers.size())
	return m_headers.at(section);
    }

  return QFileSystemModel::headerData(section, orientation, role);
}

int dfilesystemmodel::columnCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent);
  return m_headers.size();
}

QVariant dfilesystemmodel::data(const QModelIndex &index, int role) const
{
  if(index.isValid())
    {
      switch(index.column())
	{
	case 1:
	  if(role == Qt::DisplayRole)
	    return QVariant(dmisc::formattedSize(fileInfo(index).size()));
	  else
	    return QVariant();
	case 4:
	  if(role == Qt::DisplayRole)
	    return QVariant(fileInfo(index).lastRead());
	  else
	    return QVariant();
	case 5:
	  if(role == Qt::DisplayRole)
	    return QVariant(fileInfo(index).owner());
	  else
	    return QVariant();
	case 6:
	  if(role == Qt::DisplayRole)
	    return QVariant(fileInfo(index).group());
	  else
	    return QVariant();
	case 7:
	  if(role == Qt::DisplayRole)
	    {
	      QString p("");
	      QFile::Permissions permissions(fileInfo(index).permissions());

#ifdef Q_OS_UNIX
	      static QString s_array[] = {"r", "w", "x",
					  "r", "w", "x",
					  "r", "w", "x"};
	      static QFile::Permission e_array[] =
		{QFile::ReadOwner, QFile::WriteOwner, QFile::ExeOwner,
		 QFile::ReadGroup, QFile::WriteGroup, QFile::ExeGroup,
		 QFile::ReadOther, QFile::WriteOther, QFile::ExeOther};

	      for(int i = 0; i < 9; i++)
		if(permissions & e_array[i])
		  p += s_array[i];
		else
		  p += "-";
#elif defined Q_OS_WIN32
	      static QString s_array[] = {"r", "w", "x",
					  "r", "w", "x",
					  "r", "w", "x"};
	      static QFile::Permission e_array[] =
		{QFile::ReadUser, QFile::WriteUser, QFile::ExeUser,
		 QFile::ReadGroup, QFile::WriteGroup, QFile::ExeGroup,
		 QFile::ReadOther, QFile::WriteOther, QFile::ExeOther};

	      for(int i = 0; i < 9; i++)
		if(permissions & e_array[i])
		  p += s_array[i];
		else
		  p += "-";
#endif

	      return p;
	    }
	  else
	    return QVariant();
	default:
	  break;
	}
    }

  return QFileSystemModel::data(index, role);
}

void dfilesystemmodel::slotDirectoryLoaded(const QString &path)
{
  QMap<QString, QString> suffixesA;
  QMap<QString, QString> suffixesU;

  {
    QSqlQuery *query = 0;
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "applications");

    db.setDatabaseName(dooble::s_homePath + QDir::separator() +
		       "applications.db");

    if(db.open())
      {
	query = new QSqlQuery(db);
	query->exec("CREATE TABLE applications ("
		    "file_suffix TEXT PRIMARY KEY NOT NULL, "
		    "action TEXT DEFAULT NULL, "
		    "icon BLOB DEFAULT NULL)");
	query->exec("PRAGMA synchronous = OFF");
      }

    for(int i = 0; i < rowCount(index(path)); i++)
      {
	QFileInfo info;
	QModelIndex idx(index(i, 0, index(path)));

	info = fileInfo(idx);

	if(info.isFile())
	  {
	    QString suffix(info.suffix().trimmed());

	    if(dmisc::
	       canDoobleOpenLocalFile(QUrl::
				      fromLocalFile(info.
						    absoluteFilePath())))
	      continue;

	    if(!suffix.isEmpty() && !info.completeBaseName().isEmpty())
	      {
		QString action("prompt");

		if(dooble::s_applicationsActions.contains(suffix))
		  action = dooble::s_applicationsActions[suffix];

		/*
		** Updating the applications.db database while
		** the user is watching the directory that houses
		** the database will devastate Dooble.
		*/

		if(query &&
		   !dooble::s_applicationsActions.contains(suffix))
		  {
		    query->prepare
		      ("INSERT OR REPLACE INTO applications ("
		       "file_suffix, action, icon) "
		       "VALUES (?, ?, ?)");
		    query->bindValue(0, suffix);
		    query->bindValue(1, action);

		    QIcon icon(fileIcon(idx));
		    QBuffer buffer;
		    QByteArray bytes;

		    buffer.setBuffer(&bytes);
		    buffer.open(QIODevice::WriteOnly);

		    QDataStream out(&buffer);

		    out << icon.pixmap(16, QIcon::Normal, QIcon::On);
		    query->bindValue(2, bytes.toBase64());
		    buffer.close();
		    query->exec();
		  }

		if(!dooble::s_applicationsActions.contains(suffix))
		  {
		    suffixesA[suffix] = "prompt";
		    dooble::s_applicationsActions[suffix] = "prompt";
		  }
		else
		  suffixesU[suffix] = action;
	      }
	  }
      }

    if(query)
      delete query;

    db.close();
  }

  QSqlDatabase::removeDatabase("applications");

  if(!suffixesA.isEmpty())
    emit suffixesAdded(suffixesA);

  for(int i = 0; i < suffixesU.keys().size(); i++)
    emit suffixUpdated(suffixesU.keys().at(i),
		       suffixesU[suffixesU.keys().at(i)]);
}
