#include "FMPlugin.h"

#include <QtCore>
#include <QtGui/QCompleter>
#include <QtGui/QHeaderView>
#include <QtGui/QInputDialog>
#include <QtGui/QLineEdit>
#include <QtGui/QMessageBox>
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <QtGui/QToolBar>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QCheckBox>

#include <Log.h>
#include <MainSettings.h>
#include <PluginSettings.h>
#include <EditorSettings.h>

#include "ManageDlg.h"
#include "TreeView.h"

FMPlugin::FMPlugin() : QObject(), JuffPlugin() {
	model_.setSorting(QDir::DirsFirst);

	showAsTree = PluginSettings::getBool(this, "ShowAsTree", false);

	w_ = new QWidget();
	w_->setWindowTitle(tr("Files"));

	QToolBar * toolBar = new QToolBar("File Browser Tools", w_);
	//! \todo TODO/FIXME: maybe it could be configured with IconManager::instance()->size()...
	toolBar->setIconSize(QSize(16, 16));

	tree_ = new TreeView(this);
	tree_->setModel(&model_);
	tree_->setDragDropMode(QAbstractItemView::DragOnly);
	tree_->setAllColumnsShowFocus(true);
	tree_->setSelectionMode(QAbstractItemView::ExtendedSelection);
	// now configured by prefs - see showAsTree member
	//tree_->setRootIsDecorated(false);
	//tree_->setItemsExpandable(false);
	tree_->header()->resizeSection(0, 180);
	tree_->header()->resizeSection(1, 80);
	tree_->header()->resizeSection(2, 60);
	tree_->header()->resizeSection(3, 180);
	tree_->initMenu();
	
	pathEd_ = new QLineEdit("");
	backBtn_ = toolBar->addAction(QIcon(":icon_back"), tr("Go Back"), this, SLOT(back()));
	toolBar->addAction(QIcon(":icon_up"), tr("Go Up"), this, SLOT(up()));
	toolBar->addAction(QIcon(":icon_home"), tr("Go to Home Directory"), this, SLOT(home()));
	toolBar->addAction(QIcon(":icon_current"), tr("Go to current file's directory"), this, SLOT(curFileDir()));
	toolBar->addAction(QIcon(":icon_refresh"), tr("Refresh List"), &model_, SLOT(refresh()));
	toolBar->addAction(QIcon(":icon_bookmarks"), tr("Favorite Locations"), this, SLOT(favorites()));
	toolBar->addAction(QIcon(":icon_new_dir"), tr("New Directory"), this, SLOT(newDir()));

	pathEd_->setCompleter(new QCompleter(&model_));

	QVBoxLayout* vBox = new QVBoxLayout();

	vBox->setMargin(0);
	vBox->setSpacing(2);

	vBox->addWidget(toolBar);
	vBox->addWidget(pathEd_);
	vBox->addWidget(tree_);

	w_->setLayout(vBox);

	connect(tree_, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(itemDoubleClicked(const QModelIndex&)));
	connect(tree_, SIGNAL(goUp()), SLOT(up()));
	connect(pathEd_, SIGNAL(returnPressed()), SLOT(textEntered()));
	connect(&fsWatcher_, SIGNAL(directoryChanged(const QString&)), SLOT(onDirChanged(const QString&)));
	
	QString favStr = PluginSettings::getString(this, "favorites");
	if ( !favStr.isEmpty() )
		favorites_ = favStr.split(";");
	favoritesMenu_ = new QMenu(w_);
	addToFavoritesAct_ = new QAction(tr("Add current path"), this);
	manageFavoritesAct_ = new QAction(tr("Manage favorites"), this);
	connect(addToFavoritesAct_, SIGNAL(triggered()), this, SLOT(addToFavorites()));
	connect(manageFavoritesAct_, SIGNAL(triggered()), this, SLOT(manageFavorites()));
	initFavoritesMenu();

	QString lastDir = PluginSettings::getString(this, "lastDir");
	if ( lastDir.isEmpty() )
		lastDir = QDir::homePath();
	cd(lastDir, false);
	backBtn_->setEnabled(false);
	
	applySettings();
}

FMPlugin::~FMPlugin() {
	delete w_;
}

QString FMPlugin::name() const {
	return "File manager";
}

QString FMPlugin::targetEngine() const {
	return "all";
}

QString FMPlugin::description() const {
	return "Simple file manager that lets to open files without a dialog";
}

QWidgetList FMPlugin::dockList() const {
	QWidgetList wList;
	wList << w_;
	return wList;
}

bool FMPlugin::dockVisible(QWidget* w) const {
	if ( w == w_ ) {
		return true;
	}
	else {
		return JuffPlugin::dockVisible(w);
	}
}

void FMPlugin::initFavoritesMenu() {
	favoritesMenu_->clear();

	favoritesMenu_->addAction(addToFavoritesAct_);
	favoritesMenu_->addAction(manageFavoritesAct_);
	if ( !favorites_.isEmpty() )
		favoritesMenu_->addSeparator();
	foreach (QString item, favorites_) {
		favoritesMenu_->addAction(item, this, SLOT(goToFavorite()));
	}
}


void FMPlugin::cd(const QString& path, bool addToHistory /*= true*/) {
	if ( QFileInfo(path).isDir() ) {
		// remove currently watching paths
		QStringList dirs = fsWatcher_.directories();
		if ( !dirs.isEmpty() ) {
			fsWatcher_.removePaths(dirs);
		}
		
		if ( addToHistory ) {
			QString curPath = model_.filePath(tree_->rootIndex());
			history_.push(curPath);
			if ( !backBtn_->isEnabled() )
				backBtn_->setEnabled(true);
		}
		
		tree_->setRootIndex(model_.index(path));
		model_.refresh();
		pathEd_->setText(path);
		pathEd_->setToolTip(path);
		PluginSettings::set(this, "lastDir", path);
		
		// add new current path for watching
		fsWatcher_.addPath(path);
	}
}

void FMPlugin::itemDoubleClicked(const QModelIndex& index) {
	QString path = model_.filePath(index);
	if ( QFileInfo(path).isDir() ) {
		cd(path);
	}
	else {
		api()->openDoc(path);
	}
}

void FMPlugin::onDirChanged(const QString&) {
	model_.refresh();
}

void FMPlugin::back() {
	if ( !history_.isEmpty() ) {
		QString dir = history_.pop();
		if ( history_.isEmpty() )
			backBtn_->setEnabled(false);
		cd(dir, false);
	}
}

void FMPlugin::up() {
	// keep the current path
	QModelIndex curIndex = tree_->rootIndex();
	QString prevPath = model_.filePath(curIndex);
	
	QModelIndex parent = curIndex.parent();
	if ( parent.isValid() ) {
		cd(model_.filePath(parent));
		
		// select the previous dir
		QModelIndex prevIndex = model_.index(prevPath);
		if ( prevIndex.isValid() ) {
			tree_->setCurrentIndex(prevIndex);
		}
	}
}

void FMPlugin::home() {
	cd(QDir::homePath());
}

void FMPlugin::curFileDir() {
	Juff::Document* doc = api()->currentDocument();
	if ( !doc->isNull() && !doc->isNoname() ) {
		cd(QFileInfo(doc->fileName()).absolutePath());
	}
}

void FMPlugin::favorites() {
	favoritesMenu_->exec(QCursor::pos());
}

void FMPlugin::newDir() {
	QString newDirName = QInputDialog::getText(tree_, tr("New directory"), tr("Directory name"));
	if ( !newDirName.isEmpty() ) {
		QDir curDir(model_.filePath(tree_->rootIndex()));
		if ( !curDir.mkdir(newDirName) ) {
			QMessageBox::warning(tree_, tr("Warning"), 
								 tr("Couldn't create a dir named '%1'").arg(newDirName));
		}
		else {
			model_.refresh(tree_->rootIndex());
		}
	}
}


void FMPlugin::goToFavorite() {
	QAction* a = qobject_cast<QAction*>(sender());
	if ( a ) {
		cd(a->text());
	}
}

void FMPlugin::addToFavorites() {
	QString path = model_.filePath(tree_->rootIndex());
	qDebug() << path;
	if ( !favorites_.contains(path) ) {
		favorites_.append(path);
		initFavoritesMenu();
		PluginSettings::set(this, "favorites", favorites_.join(";"));
	}
}

void FMPlugin::manageFavorites() {
	ManageDlg dlg(tree_, this);
	dlg.exec();
	QString favStr = PluginSettings::getString(this, "favorites");
	if ( !favStr.isEmpty() )
		favorites_ = favStr.split(";");
	else
		favorites_ = QStringList();
	initFavoritesMenu();
}

void FMPlugin::textEntered() {
	if ( QFileInfo(pathEd_->text()).isDir() )
		cd(pathEd_->text());
	else
		pathEd_->setText(model_.filePath(tree_->rootIndex()));
}

void FMPlugin::onDocSaved(const QString& fileName) {
	model_.refresh(model_.index(QFileInfo(fileName).absolutePath()));
}

void FMPlugin::applySettings() {
	QPalette plt = tree_->palette();
	plt.setColor(QPalette::Base, EditorSettings::get(EditorSettings::DefaultBgColor));
	plt.setColor(QPalette::Text, EditorSettings::get(EditorSettings::DefaultFontColor));
//	plt.setColor(QPalette::Highlight, EditorSettings::get(EditorSettings::SelectionBgColor));
//	plt.setColor(QPalette::HighlightedText, TextDocSettings::selectionTextColor());
	tree_->setPalette(plt);
	pathEd_->setPalette(plt);

	PluginSettings::set(this, "ShowAsTree", showAsTree);
	tree_->setRootIsDecorated(showAsTree);
	tree_->setItemsExpandable(showAsTree);
}

QWidget * FMPlugin::settingsPage() const
{
	QWidget * cfg = new QWidget();
	QVBoxLayout * l = new QVBoxLayout();
	cfg->setLayout(l);

	QCheckBox * treeCheckBox = new QCheckBox(tr("Show Directory Structure in a Tree"), cfg);
	treeCheckBox->setChecked(showAsTree);
	connect(treeCheckBox, SIGNAL(toggled(bool)), this, SLOT(treeCheckBox_toggled(bool)));

	l->addWidget(treeCheckBox);
	l->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding));
	return cfg;
}

void FMPlugin::treeCheckBox_toggled(bool value)
{
	showAsTree = value;
}

Q_EXPORT_PLUGIN2(fm, FMPlugin)
