#include "file_manager.h"

#include "shared.h"


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


PIStringList FileManager::TileDir::selectedNames() const {
	PIStringList ret;
	PIMutexLocker ml(e_mutex);
	PIVector<int> sind = selected.toVector();
	for (const auto 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 (!(is_right && remote_mode)) updateDir();
		pass = true;
		break;
	case PIKbdListener::F5:
		if (selected.isEmpty()) selected << cur;
		if (!askQuestion("Copy selected files?")) return true;
		setFocus();
		// piCoutObj << "remote" << remote_mode;
		if (remote_mode)
			actionRequest(is_right, Copy, selectedNames());
		else
			actionRequest(is_right, LocalCopy, selectedNames());
		break;
	case PIKbdListener::F6:
		if (key.modifiers[PIKbdListener::Shift]) {
			if (selected.isEmpty()) selected << cur;
			if (!askQuestion("Crypt selected files?")) return true;
			setFocus();
			if (remote_mode)
				actionRequest(is_right, Crypt, selectedNames());
			else
				actionRequest(is_right, LocalCrypt, selectedNames());
		}
		break;
	case PIKbdListener::F7:
		nd = askUserInput("Enter new directory name:");
		setFocus();
		if (nd.isEmpty()) return true;
		if (is_right && remote_mode)
			actionRequest(is_right, 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 (is_right && remote_mode) {
			actionRequest(is_right, 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 (!(is_right && remote_mode)) {
				// 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;
	}
	//	piCout << is_right << remote_mode << pass;
	if (is_right && remote_mode && 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> 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() {
	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() {
	lock();
	PIMutexLocker ml(e_mutex);
	content.clear();
	PIChar t;
	CharFlags cf = 0;
	Color cc     = Default;
	PIString fcol, scol;
	for (const auto & 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;
	TileList::resizeEvent(w, h);
}


FileManager::FileManager() {
	setName("FileManager");
	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::fromNumber(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);
	}
	panels[1]->is_right = true;
	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");
	for (const auto & 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::setLocal() {
	if (panels[1]->remote_mode) setRemoteDir(panels[0]->dir.absolutePath());
	panels[0]->remote_mode = panels[1]->remote_mode = false;
}


void FileManager::setRemote() {
	panels[0]->remote_mode = panels[1]->remote_mode = true;
}


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();
}


int FileManager::selectedPanel() const {
	for (int i = 0; i < 2; i++)
		if (panels[i]->hasFocus()) return i;
	return -1;
}


PIStringList FileManager::selectedRemote() const {
	PIStringList ret;
	panels[1]->lock();
	PIVector<int> sil = panels[1]->selected.toVector();
	for (const auto 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;
}
