package hh.dejsem;

import android.content.Context;
import android.os.Environment;
import android.support.v4.provider.DocumentFile;

import java.io.File;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;

import hh.dejsem.fm.TransferOverview;
import hh.dejsem.net.NetConnSrv;
import hh.dejsem.net.NetNode;
import hh.dejsem.net.NetUDP;
import hh.dejsem.net.SrvCmd;
import hh.lib.D;

/* TODO
- problémy k 30.10.2018
	- když se ztratí Notification, nedá se obnovit i když všechny procesy běží normálně dál
	- po server upload se nerefreshuje file list
- kontejner roznášející libovolné objekty
- abend msg s bezpodmínečným abendem
- StrictMode.ThreadPolicy
- konsolidace K
- optimalizace cachingu
*/

public class K {
	/*----------------------------------------------------------
	 * konstanty
	 *---------------------------------------------------------*/
	// velký timeout má smysl u pomalého výstupu, po němž následuje vstup - data se odlejí do bufferu a přejde se na čtení,
	//      ale vstup z protější strany přijde, až když odejseme celý buffer pomalým výstupem na protější stranu}
	public static final int acceptTO = 60 * 1000;  // peer server accept timeout in msecs
	public static final int socketTO = 33 * 1000;  // socket IO timeout in msecs

	public static final int BASE_PORT_NUM = 42000;
	public static final int buffSize = 8192;       // data transfer buffer size

	public static final String ACTION_KEY = "ACTION";
	public static final String TXT_KEY = "TXT";
//	public static final String SRC_KEY = "SRC";
	public static final String PORT_KEY = "SERVER_PORT";
	public static final String FILES_FROM_KEY = "FILES_FROM";
	public static final String FILE_TO_KEY = "FILE_TO";
	public static final String FN_KEY = "FILE_NAME";
	public static final String STREAM_KEY = "INTENT_STREAM";
	public static final String MIME_TYPE_KEY = "MIME_TYPE";
	public static final String LFN_KEY = "LOCAL_FILE_NAME";
	public static final String RFN_KEY = "REMOTE_FILE_NAME";

	public static final String SD_CARD_MOUNT_POINT = "/storage/extSdCard/";
	public static DocumentFile SD_CARD_ROOT_DOC_FILE = null;   // sd card root odsouhlasený na začátku a uložený v SharedPrefs

	public static final String CACHEFNR_KEY = "remoteFileListCache";
	public static final String CACHEFNL_KEY = "localFileListCache";
	public static final String CACHED_LOC_CWD_KEY = "CACHED_LOC_CWD";
	public static final String CACHED_REM_CWD_KEY = "CACHED_REM_CWD";

	public static final String HISTORY_TAG = "HISTORY";
	public static final String NET_INFO_TAG = "NET_INFO";
	public static final String LAST_MILE_TAG = "LAST_MILE";
	public static final String UPLOAD_TAG = "UPLOAD";

	public static final String FM_SRV_TAG = "fmsrv";
	public static final String FM_PEER_TAG = "fmpeer";
	public static final String FM_DIALOG_SAVED_STATUS_KEY = "DIALOG_SAVED_STATUS";
	public static final String FM_LOC_SAVED_POSITION_KEY = "FM_LOC_SAVED_POSITION";
	public static final String FM_LOC_SAVED_SELECTION_KEY = "FM_LOC_SAVED_SELECTION";
	public static final String FM_SRV_SAVED_POSITION_KEY = "FM_SRV_SAVED_POSITION";
	public static final String FM_SRV_SAVED_SELECTION_KEY = "FM_SRV_SAVED_SELECTION";
	public static final String FM_SAVED_CWD_KEY = "FM_SAVED_CWD";
	public static final String FN_RESERVED_CHARS_REGEX = "[\"*|:<>\\?]";
	public static final String FS_KIND_KEY = "FS_KIND";

	/**
	 * request codes
	 */
	public static final int MAIN_REFRESH = 16;
	public static final int HISTORY = 17;
	public static final int CHOOSE_SD_CARD_TREE = 18;
	public static final int GETPW = 19;

	public static final int LOC_FS = 72;
	public static final int SRV_FS = 82;

	public static final int MSG_COPY_TO_SRV = 224;
	public static final int MSG_COPY_FROM_SRV = 225;
	public static final int MSG_COPY_TO_PEER = 226;
	public static final int MSG_COPY_FROM_PEER = 227;
	public static final int MSG_EXPOSE_TO_SRV = 228;

	public static final int MSG_TEST = 230;
	public static final int MSG_REFRESH_LOC = 231;     // refresh local  FS dir list
	public static final int MSG_REFRESH_SRV = 232;     // refresh remote FS dir list
	public static final int MSG_WATCH_PROGRESS = 233;

	public static final int MSG_END = 240;
	public static final int MSG_PING = 241;
	public static final int MSG_EXPOSE = 242;
	public static final int MSG_SVC_ABEND = 243;
	public static final int MSG_SVC_WARNING = 244;
	public static final int MSG_SVC_INFO = 245;

	public static final int TRANSFER_NOTIFICATION_ID = 300;
	public static final int TRANSFER_PIN_NOTIFICATION = 301;
	public static final int TRANSFER_DISPLAY_LIST = 302;
	public static final int TRANSFER_WARNING = 303;
	public static final int TRANSFER_ABEND = 304;
	public static final int TRANSFER_DISPLAY_TEST = 305;
	public static final int TRANSFER_SEND_URI = 306;

	public static final int FM_ACTION_DELETE = 400;
	public static final int FM_ACTION_RENAME = 401;
	public static final int FM_ACTION_CREATE = 402;
	public static final int FM_MOVE_DEST = 403;
	public static final int FM_MOVE_CANCEL = 404;
	public static final int FM_MENU_SERVER = 405;
	public static final int FM_MENU_LOCAL = 406;
	public static final int FM_MENU_PEER = 406;

	public static final String UDP_ADVERT_KEY = "PEER_IP";
	public static final String CRYPT_ALG = "DESede/ECB/NoPadding";

	public static final int CRYPT_KEYLEN = 24;
	public static int UDP_PORT = 4242;    // dejsem 4224, dejsem 4242

	public static final String testText = "<---- 150chars/180bytes of test text ---------------- " +
			"příliš žluťoučký kůň úpěl ďábelské kódy ------------ " +
			"PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ KÓDY -->";
	public static final String passId = "word";
	private static final String ext_stg = Environment.getExternalStorageDirectory().getAbsolutePath();
	public static final String home = ext_stg + "/_HH";
	public static final String dnld = ext_stg + "/Download";

	public static void cmdConnClose(D d) {
		if (cmdConn != null && cmdConn.netIO.isConnected())
			try { SrvCmd.CLOSE.exec(d, null); }
			catch(Exception e) { d.abendMsg("closing cmd connection", e); }
	}

	public static boolean blocked() { return netInUse; }

	public static String printShared() {
		return String.format("D.netNode=%s, D.cmdConn=%s, D.transfProgress=%s", netNode, cmdConn, transfProgress);
	}

	public static class NotCreated extends Exception {
		public NotCreated() { super("not created"); }
		public NotCreated(String msg) { super(msg); }
	}

	public static class NotRenamed extends Exception { NotRenamed() { super("not renamed"); } }

	public static class NotDeleted extends Exception { NotDeleted() { super("not deleted"); } }

	public static class NothingSelected extends Exception { public NothingSelected() { super("nothing selected"); } }

	public static class AllPortsBusy extends Exception { public AllPortsBusy() { super("all server ports busy"); } }

	public static class NotCompleted extends Exception { public NotCompleted() { super("not completed"); } }

	public static class AlreadyExists extends Exception { AlreadyExists(String msg) { super(msg); } }

	public static class EntryNotFound extends Exception {}

	public static class NoPeerListening extends Exception { public NoPeerListening() { super("no peer is listening"); } }

	public static class IntentionalABEND extends Exception { public IntentionalABEND(String msg) { super(msg); } }

	/**
	 * handle Abnormal End information
	 */
	public static class Abend extends Exception {
		/*----------------------------------------------------------
		 * handle Abnormal End information
		 *----------------------------------------------------------*/
		Abend() { this(""); 	}

		Abend(String m) {
			this(m, null);
		}

		Abend(String m, Throwable t) {
			super(m, t);
			if (t != null) t.printStackTrace();
		}
	}

	/**
	 * handle Quiet Abnormal End information
	 */
	public static class End extends Exception {
		public End() {
			this(null, null);
		}

		public End(String m) {
			this(m, null);
		}

		public End(Throwable t) { this(null, t); }

		public End(String m, Throwable t) {
			super(m, t);
			if(t != null) t.printStackTrace();
		}
	}

	public enum HistOrder {TEXT, SIZE, DATE}

	public enum DirListOrder {
		NAME_ASC(0), NAME_DESC(1),
		SIZE_ASC(2), SIZE_DESC(4),
		DATE_ASC(6), DATE_DESC(7);

		DirListOrder(int value) {
			this.value = value;
		}

		private final int value;

		public int value() {
			return value;
		}
	}

	public enum LongTaskAction {
		BATCHEND("BATCHEND"), PUSHFIEX("PUSHFIEX"), PUSHSTEX("PUSHSTEX"),
		PULLFILE("PULLFILE"), PUSHFILE("PUSHFILE");

		LongTaskAction(String action) {
			this.action = action;
		}

		public final String action;

		public String act() {
			return action;
		}
	}

	/**----------------------------------------------------------
	 * shared values
	 * ----------------------------------------------------------*/
	public static final Object synchron = new Object();
	public static Context app = null;
	public static TitleBar title;
	public static HashMap<String, Object> base = new HashMap<String, Object>();
	// cache file se využívá pro caching remote filelist (fn + attributes)
	// io-file proto, že se pro network i file využívá tentýž interface
	public static File cacheFileR = null;
	public static String word = "";
	// public static DialogInterface.OnClickListener dialogLstnr = null;
	public static TransferOverview transfProgress = null;
//	public static HistList histlist = null;     // zkouším nepoužívat
	public static DatagramPacket UDPpacket = null;
	public static DatagramSocket UDPsocket = null;
	public static NetUDP netUDp = null;
	public static NetConnSrv cmdConn = null;
	public static boolean netInUse = false;	// network operation in progress	<== not used currently
	public static NetNode netNode = null;
	public static SdUri sdUri = null;

	private static K k = null;
	private K() {}

	public static K getInstance() {
		if(k == null) k = new K();
		return k;
	}

	public static void prepTransferOverview(D d) { if (K.transfProgress == null) K.transfProgress = new TransferOverview(d); }
}