#include "file_manager.h"
#include "shared.h"
#include "daemon.h"

extern PIScreen screen;


FileManager::TileDir::TileDir(): TileList() {
	label_path = 0;
	selection_mode = TileList::MultiSelection;
	dir = PIDir::current();
	resized = remote = remote_mode = false;
}


PIStringList FileManager::TileDir::selectedNames() const {
	PIStringList ret;
	PIMutexLocker ml(e_mutex);
	PIVector<int> sind = selected.toVector();
	piForeachC (int i, sind)
		ret << entries[i].name();
	ret.removeOne("..");
	return ret;
}


bool FileManager::TileDir::keyEvent(PIKbdListener::KeyEvent key) {
	bool pass = false;
	PIString nd;
	switch (key.key) {
	case 'R': if (!remote) updateDir(); pass = true; break;
	case PIKbdListener::F5:
		if (remote_mode) {
			if (selected.isEmpty())
				selected << cur;
			if (!askQuestion("Copy selected files?")) return true;
			setFocus();
			actionRequest(remote, Copy, selectedNames());
		}
		break;
	case PIKbdListener::F7:
		nd = askNewDir();
		setFocus();
		if (nd.isEmpty()) return true;
		if (remote)
			actionRequest(remote, MkDir, nd);
		else {
			PIDir::make(dir.absolutePath() + PIDir::separator + nd);
			updateDir();
		}
		pass = true;
		break;
	case PIKbdListener::F8:
		if (selected.isEmpty())
			selected << cur;
		if (!askQuestion("Delete selected?")) {
			setFocus();
			return false;
		}
		setFocus();
		if (remote) {
			actionRequest(remote, Remove, selectedNames());
		} else {
			removeFiles(dir, selectedNames());
			selected.clear();
			updateDir();
		}
		pass = true;
		break;
	case PIKbdListener::Return:
		{
		e_mutex.lock();
		bool ud = false;
		if (cur < entries.size_s() && cur >= 0) {
			if (!remote) {
				//piCout << entries[cur];
				if (entries[cur].isDir()) {
					prev_pos[dir.path()] = PIPair<int, int>(cur, offset);
					dir.cd(entries[cur].name());
					PIPair<int, int> cp = prev_pos.value(dir.path());
					cur = cp.first;
					offset = cp.second;
					selected.clear();
					ud = true;
				}
			}
			pass = true;
		}
		e_mutex.unlock();
		if (ud) updateDir();
		}
		break;
	}
	if (remote && pass) {
		((void(*)(void*,PIKbdListener::KeyEvent))key_func)(fm, key);
		return true;
	}
	return TileList::keyEvent(key);
}


void FileManager::TileDir::lock() {
	if (screen && !resized) ((PIScreen*)screen)->lock();
}


void FileManager::TileDir::unlock() {
	if (screen && !resized) ((PIScreen*)screen)->unlock();
}


void FileManager::TileDir::showReading() {
	PIMutexLocker ml(e_mutex);
	cur = -1;
	offset = 0;
	entries.clear();
	content.resize(1);
	content[0] = Row("... Reading ...", CellFormat());
}


void FileManager::TileDir::setContent(const PIVector<PIFile::FileInfo> & l) {
	PIMutexLocker ml(e_mutex);
	PIVector<PIFile::FileInfo> el = dir.entries(), fl, dl;
	entries.clear();
	if (l.isEmpty()) {
		PIFile::FileInfo fi;
		fi.path = "..";
		fi.flags |= PIFile::FileInfo::DotDot | PIFile::FileInfo::Dir;
		entries << fi;
	} else {
		bool root = dir.path() == PIDir::separator;
		for (int i = 0; i < l.size_s(); ++i) {
			if (l[i].name() == ".") continue;
			if (l[i].name() == "..") {
				if (!root) dl.push_front(l[i]);
				continue;
			}
			if (l[i].isDir()) dl << l[i];
			else fl << l[i];
		}
		entries << dl << fl;
	}
}


void FileManager::TileDir::updateDir() {
	//if (!enabled) return;
	lock();
	int pc = cur, po = offset;
	showReading();
	unlock();
	setContent(dir.entries());
	if (label_path) {
		label_path->content.resize(1);
		label_path->content[0].first = dir.absolutePath();
	}
	cur = pc;
	offset = po;
	buildNames();
}


void FileManager::TileDir::buildNames() {
	//if (!enabled) return;
	lock();
	PIMutexLocker ml(e_mutex);
	content.clear();
	PIChar t;
	CharFlags cf = 0;
	Color cc = Default;
	PIString fcol, scol;
	piForeachC (PIFile::FileInfo & e, entries) {
		if (e.isDir()) {
			t = '/';
			cf = Bold;
			scol = " dir";
		} else {
			if (e.perm_user.exec || e.perm_group.exec || e.perm_other.exec) {
				cf = Bold;
				cc = Green;
				t = '*';
			} else {
				t = ' ';
				cc = Default;
				cf = 0;
			}
			scol = PIString::readableSize(e.size);
		}
		if (e.isSymbolicLink() && (t != '*')) t = '~';
		scol = scol.expandRightTo(9, ' ') + "| " + e.time_modification.toString("dd.MM hh:mm:ss") + " | "
				+ e.perm_user.toString() + " " + e.perm_group.toString() + " " + e.perm_other.toString();
		fcol = t + e.name();
		if (fcol.size_s() >= width - 2 - scol.size_s())
			fcol = fcol.left(width - 5 - scol.size_s()) + "...";
		fcol.expandRightTo(width - 1 - scol.size_s(), ' ');
		content << Row(fcol + scol, CellFormat(cc, Transparent, cf));
	}
	unlock();
}


void FileManager::TileDir::sizeHint(int & w, int & h) const {
	w = h = 4;
}


void FileManager::TileDir::resizeEvent(int w, int h) {
	resized = true;
	buildNames();
	resized = false;
}




FileManager::FileManager(Daemon * d) {
	setName("FileManager");
	del_commit = false;
	daemon = d;
	CONNECTU(&screen, keyPressed, this, keyEvent)
	//dir.setDir("/home/peri4/Documents");
	TileSimple * tl;
	
	tile_root = new PIScreenTile();
	tile_root->direction = Vertical;
	PIScreenTile * pt = new PIScreenTile();
	pt->direction = Horizontal;
	pt->spacing = 1;
	pt->back_format.color_back = Cyan;
	for (int i = 0; i < 2; ++i) {
		PIScreenTile * panel = new PIScreenTile();
		TileSimple * plabel = new TileSimple();
		plabel->size_policy = Fixed;
		plabel->maximumWidth = 1;
		panel->direction = Vertical;
		panels[i] = new TileDir();
		panels[i]->fm = this;
		panels[i]->key_func = (void*)tileKey_s;
		panels[i]->setName("file panel " + PIString(i));
		panels[i]->label_path = plabel;
		CONNECTU(panels[i], actionRequest, this, actionRequest)
		panel->addTile(plabel);
		panel->addTile(panels[i]);
		panels[i]->updateDir();
		pt->addTile(panel);
	}
	tile_root->addTile(pt);
	
	PIScreenTile * labels = new PIScreenTile();
	labels->size_policy = Fixed;
	labels->direction = Horizontal;
	PIVector<SSPair> ll;
	ll << SSPair(" Esc", "Exit") << SSPair(" F5", "Copy") << SSPair(" F6", "Move") << SSPair(" F7", "MkDir") << SSPair(" F8", "Delete");
	piForeachC (SSPair & l, ll) {
		tl = new TileSimple(); labels->addTile(tl);
		tl->content << TileSimple::Row(l.first, CellFormat(White, Transparent, Bold));
		tl = new TileSimple(); labels->addTile(tl);
		tl->content << TileSimple::Row(l.second, CellFormat(Black, Cyan));
	}
	tl = new TileSimple(); labels->addTile(tl);
	tl->size_policy = Expanding;
	tile_root->addTile(labels);
	
}


PIScreenTile * FileManager::tile() const {
	return tile_root;
}


void FileManager::setRemoteDir(const PIString & d) {
	panels[1]->dir.setDir(d);
	if (panels[1]->label_path) {
		panels[1]->label_path->content.resize(1);
		panels[1]->label_path->content[0].first = panels[1]->dir.path();
	}
}


void FileManager::setRemoteContent(const PIVector< PIFile::FileInfo > & el) {
	panels[1]->setContent(el);
	panels[1]->buildNames();
}


PIStringList FileManager::selectedRemote() const {
	PIStringList ret;
	panels[1]->lock();
	PIVector<int> sil = panels[1]->selected.toVector();
	piForeachC (int i, sil)
		ret << panels[1]->entries[i].path;
	panels[1]->unlock();
	return ret;
}


PIFile::FileInfo FileManager::currentRemoteEntry() const {
	if ((panels[1]->cur < 0) || (panels[1]->cur >= panels[1]->content.size_s())) return PIFile::FileInfo();
	return panels[1]->entries[panels[1]->cur];
}


void FileManager::remoteSaveDir() {
	panels[1]->prev_pos[panels[1]->dir.path()] = PIPair<int, int>(panels[1]->cur, panels[1]->offset);
}


void FileManager::remoteRestoreDir() {
	PIPair<int, int> cp = panels[1]->prev_pos.value(panels[1]->dir.path());
	panels[1]->selected.clear();
	panels[1]->cur = cp.first;
	panels[1]->offset = cp.second;
	if ((panels[1]->cur < 0) || (panels[1]->cur >= panels[1]->content.size_s()))
		panels[1]->cur = 0;
}


void FileManager::keyEvent(PIKbdListener::KeyEvent key) {
	if (!tile_root->visible) return;
	if (screen.dialogTile()) return;
	switch (key.key) {
	case PIKbdListener::Esc:
		menuRequest();
		break;
	default: break;
	}
	/*if (!enabled) return;
	if (key.key == 'D') {
		if (cur >= files.size_s() || cur < 0) return;
		if (del_commit) {
			piForeachC (PIString & f, selected) {
				PIFile::remove(dir.absolutePath() + PIDir::separator + f);
				//piCout << "remove" << (dir.absolutePath() + PIDir::separator + f);
			}
			selected.clear();
			updateDir();
			console.clearCustomStatus();
			del_commit = false;
		} else {
			if (selected.isEmpty()) selected << files[cur].path;
			console.addCustomStatus("Delete " + PIString(selected.size_s()) + " file, are you sure? D as yes");
			del_commit = true;
		}
		updateConsole();
		return;
	}
	console.clearCustomStatus();
	del_commit = false;
	PIStringList nsel;
	switch (key.key) {
	case PIKbdListener::UpArrow:
		cur--;
		if (cur < 0) cur = 0;
		if (cur - offset < 3) offset--;
		if (offset < 0) offset = 0;
		updateConsole();
		break;
	case PIKbdListener::Space:
		if (cur < 0 || cur >= files.size_s()) return;
		if (selected.contains(files[cur].path)) selected.removeOne(files[cur].path);
		else selected << files[cur].path;
	case PIKbdListener::DownArrow:
		cur++;
		if (cur >= files.size_s()) cur = files.size_s() - 1;
		if (cur - offset >= height - 3) offset++;
		if (offset >= files.size_s() - height) offset = files.size_s() - height;
		updateConsole();
		//piCout << offset << files.size_s() << height;
		break;
	case PIKbdListener::Home:
		cur = offset = 0;
		updateConsole();
		break;
	case PIKbdListener::End:
		cur = files.size_s() - 1;
		offset = files.size_s() - height;
		updateConsole();
		//piCout << offset << files.size_s() << height;
		break;
	case PIKbdListener::Return:
		if (cur < files.size_s() && cur >= 0) {
			piCout << files[cur];
			if (files[cur].isDir()) {
				prev_pos[dir.path()] = cur;
				prev_off[dir.path()] = offset;
				dir.cd(files[cur].name());
				cur = prev_pos.value(dir.path(), 0);
				offset = prev_off.value(dir.path(), 0);
				selected.clear();
				updateDir();
				updateConsole();
			}
		}
		break;
	case 'A':
		selected.clear();
		piForeach (PIFile::FileInfo & e, files)
			selected << e.path;
		updateConsole();
		break;
	case 'R':
		updateDir();
		piForeach (PIFile::FileInfo & e, files)
			if (selected.contains(e.path))
				nsel << e.path;
		selected = nsel;
		updateConsole();
		break;
	case PIKbdListener::Esc:
		//selected.clear();
		//updateConsole();
		menuRequest();
		break;
	default: break;
	}*/
}


void FileManager::updateConsole() {
	/*if (!enabled) return;
	startTab(2);
	console.addString("File manager", 1, Yellow | Inverse);
	console.addString("Path: " + dir.absolutePath(), 1, Green | Inverse | Bold);
	console.addString("Name", 1, Green | Inverse | Bold);
	console.addString(" ", 2, Yellow | Inverse);
	console.addString(" ", 2, Green | Inverse);
	console.addString(" ", 2, Green | Inverse);
	buildNames();
	console.addString("A - select all, D - remove, R - refresh, Esc - exit", 1, Green | Inverse | Bold);
	finishTab();*/
}
