package hh.dejsem.fm;

import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;

import hh.dejsem.K;
import hh.lib.D;

/**
 * base class of file manager operations on local/remote files
 * <p>
 * ● instance holds info about underlying file system in form of stack of lists of nested directories
 **/
abstract class FM {
	D d;
	FileList cwdFl = null;          // file list of cwd
	LinkedList<FileList> stack = new LinkedList<FileList>();
	HashMap<String, FileList> cache = new HashMap<String, FileList>();

	FM(D d) { this.d = d.klon(this); }

	abstract long getFreeSpace(String path) throws Exception;

	abstract EntitySize reckon(String[] sel) throws Exception;

	abstract void doCreateDir(String dirName) throws Exception;

	abstract void renameSelected(String to) throws Exception;

	void iterateMove(String to) throws Exception {
		for(File f: getArrSelection()) doMove(f.getPath(), to);
		clearSelected();
		stack.clear();
		FragFM.refreshNotify(FMLocal.class.isInstance(this));
	}

	abstract void doMove(String from, String to) throws Exception;

	abstract void iterateDelete();

	void stackAndEnterDir(String ncwd) {
		if(cwdFl != null) stack.push(cwdFl);
		if(stack.size() > 6) stack.removeLast();
		enterDir(ncwd);
	}

	void enterDir() { enterDir(cwdFl.dirName); }

	void enterDir(String dirName) {
		if(d.ll(4)) d.l("enter dir=" + dirName);
		cwdFl = getFileList(dirName);
	}

	FileList cacheFileList(FileList fileList) {
		cache.put(fileList.dirName, fileList);
		return fileList;
	}

	/*void goUp() {
		if(stack.empty()) {
			String parent = new File(cwdFl.dirName).getParent();
			if(parent == null) {
				parent = "/";
				if(fmsrv.cacheFileR != null) fmsrv.cacheFileR.delete(); }
			try { enterDir(parent); } catch(Exception e) { d.abendMsg("entering dir", e); }
		}
		else cwdFl = stack.pop();
	}*/

	void goUp() {
		String parent = new File(cwdFl.dirName).getParent();
		if(parent == null) {
			parent = "/";
			if(K.cacheFileR != null) K.cacheFileR.delete(); }
		stackAndEnterDir(parent);
	}

	abstract FileList createFileList(String cwdN);

	int getCurrListPos() { return cwdFl.getCurrPos(); }

	void setCurrListPos(int pos) { cwdFl.setCurrPos(pos); }

	FileList getFileList(String cwdN) {
		if(cache.containsKey(cwdN)) return cache.get(cwdN);
		else return createFileList(cwdN);
	}

	FileListAdapter getListAdapter() { return cwdFl.getListAdapter(); }

	String getFnByPos(int pos) { return cwdFl.getFnByPos(pos); }

	String fullPath(String fn) { return getPath(getCwdName(), fn); }

	String getPath(String fp, String fn) { return new File(fp, fn).getPath(); }

	String getCwdName() { return cwdFl.dirName; }

	File[] getArrSelection() { return cwdFl.getArrSelection(); }

	String[] getStrArrSelection() { return cwdFl.getStrArrSelection(); }

	void clearSelected() { cwdFl.clearSelected(); }

	void setSelection(int pos) { cwdFl.setSelection(pos, true);}

	File[] setArrSelection() { return cwdFl.getArrSelection(); }

	void setStrArrSelection(String[] selection) { cwdFl.setStrArrSelection(selection); }

	void setStrSelection(String fn) { cwdFl.setStrSelection(fn, true); }

	FileAttrs getFa(String fn) { return cwdFl.getFa(fn); }

	boolean isDir(String fn) { return cwdFl.get(fn).isDir(); }

	boolean isFile(String fn) { return !isDir(fn); }

	EntitySize determineSizeOf() throws Exception {
		String[] sel = getStrArrSelection();
		return reckon(sel);
	}

	void refreshFileList() {
		if(d.ll(4)) d.l("refreshing file list, dir=" + cwdFl.dirName);
		deleteCache(cwdFl.dirName);
		cwdFl.populateFileList();
		cacheFileList(cwdFl);
	}

	abstract void deleteCache(String fp);
}