'use strict'

/* global __, App, Headlines, xhrPost, dojo, dijit, Form, fox, PluginHost, Notify, $$ */

const	Feeds = {
	counters_last_request: 0,
	_active_feed_id: undefined,
	_active_feed_is_cat: false,
	infscroll_in_progress: 0,
	infscroll_disabled: 0,
	_infscroll_timeout: false,
	_search_query: false,
	last_search_query: [],
	_viewfeed_wait_timeout: false,
	_counters_prev: [],
	// NOTE: this implementation is incomplete
	// for general objects but good enough for counters
	// http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html
	counterEquals: function(a, b) {
		// Create arrays of property names
		const aProps = Object.getOwnPropertyNames(a);
		const bProps = Object.getOwnPropertyNames(b);

		// If number of properties is different,
		// objects are not equivalent
		if (aProps.length != bProps.length) {
			return false;
		}

		for (let i = 0; i < aProps.length; i++) {
			const propName = aProps[i];

			// If values of same property are not equal,
			// objects are not equivalent
			if (a[propName] !== b[propName]) {
				return false;
			}
		}

		// If we made it this far, objects
		// are considered equivalent
		return true;
	},
	resetCounters: function () {
		this._counters_prev = [];
	},
	parseCounters: function (elems) {
		PluginHost.run(PluginHost.HOOK_COUNTERS_RECEIVED, elems);

		for (let l = 0; l < elems.length; l++) {

			if (Feeds._counters_prev[l] && this.counterEquals(elems[l], this._counters_prev[l])) {
				continue;
			}

			const id = elems[l].id;
			const kind = elems[l].kind;
			const ctr = parseInt(elems[l].counter);
			const error = elems[l].error;
			const has_img = elems[l].has_img;
			const updated = elems[l].updated;

			if (id == "global-unread") {
				App.global_unread = ctr;
				App.updateTitle();
				continue;
			}

			if (id == "subscribed-feeds") {
				/* feeds_found = ctr; */
				continue;
			}

			/*if (this.getUnread(id, (kind == "cat")) != ctr ||
					(kind == "cat")) {
			}*/

			this.setUnread(id, (kind == "cat"), ctr);
			this.setValue(id, (kind == "cat"), 'auxcounter', parseInt(elems[l].auxcounter));
			this.setValue(id, (kind == "cat"), 'markedcounter', parseInt(elems[l].markedcounter));

			if (kind != "cat") {
				this.setValue(id, false, 'error', error);
				this.setValue(id, false, 'updated', updated);

				if (id > 0) {
					if (has_img) {
						this.setIcon(id, false,
							App.getInitParam("icons_url") + "/" + id + ".ico?" + has_img);
					} else {
						this.setIcon(id, false, 'images/blank_icon.gif');
					}
				}
			}
		}

		Headlines.updateCurrentUnread();

		this.hideOrShowFeeds(App.getInitParam("hide_read_feeds"));
		this._counters_prev = elems;

		PluginHost.run(PluginHost.HOOK_COUNTERS_PROCESSED);
	},
	reloadCurrent: function(method) {
		if (this.getActive() != undefined) {
			console.log("reloadCurrent: " + method);

			this.open({feed: this.getActive(), is_cat: this.activeIsCat(), method: method});
		}
		return false; // block unneeded form submits
	},
	openNextUnread: function() {
		const is_cat = this.activeIsCat();
		const nuf = this.getNextUnread(this.getActive(), is_cat);
		if (nuf) this.open({feed: nuf, is_cat: is_cat});
	},
	toggle: function() {
		Element.toggle("feeds-holder");

		const splitter = $("feeds-holder_splitter");

		Element.visible("feeds-holder") ? splitter.show() : splitter.hide();

		dijit.byId("main").resize();

		Headlines.updateCurrentUnread();
	},
	cancelSearch: function() {
		this._search_query = "";
		this.reloadCurrent();
	},
	requestCounters: function() {
		xhrPost("backend.php", {op: "rpc", method: "getAllCounters", seq: App.next_seq()}, (transport) => {
			App.handleRpcJson(transport);
		});
	},
	reload: function() {
		try {
			Element.show("feedlistLoading");

			this.resetCounters();

			if (dijit.byId("feedTree")) {
				dijit.byId("feedTree").destroyRecursive();
			}

			const store = new dojo.data.ItemFileWriteStore({
				url: "backend.php?op=pref_feeds&method=getfeedtree&mode=2"
			});

			// noinspection JSUnresolvedFunction
			const treeModel = new fox.FeedStoreModel({
				store: store,
				query: {
					"type": App.getInitParam('enable_feed_cats') ? "category" : "feed"
				},
				rootId: "root",
				rootLabel: "Feeds",
				childrenAttrs: ["items"]
			});

			// noinspection JSUnresolvedFunction
			const tree = new fox.FeedTree({
				model: treeModel,
				onClick: function (item/*, node*/) {
					const id = String(item.id);
					const is_cat = id.match("^CAT:");
					const feed = id.substr(id.indexOf(":") + 1);
					Feeds.open({feed: feed, is_cat: is_cat});
					return false;
				},
				openOnClick: false,
				showRoot: false,
				persist: true,
				id: "feedTree",
			}, "feedTree");

			const tmph = dojo.connect(dijit.byId('feedMenu'), '_openMyself', function (event) {
				console.log(dijit.getEnclosingWidget(event.target));
				dojo.disconnect(tmph);
			});

			$("feeds-holder").appendChild(tree.domNode);

			const tmph2 = dojo.connect(tree, 'onLoad', function () {
				dojo.disconnect(tmph2);
				Element.hide("feedlistLoading");

				try {
					Feeds.init();
					App.setLoadingProgress(25);
				} catch (e) {
					App.Error.report(e);
				}
			});

			tree.startup();
		} catch (e) {
			App.Error.report(e);
		}
	},
	init: function() {
		console.log("in feedlist init");

		App.setLoadingProgress(50);

		//document.onkeydown = (event) => { return App.hotkeyHandler(event) };
		//document.onkeypress = (event) => { return App.hotkeyHandler(event) };
		window.onresize = () => { Headlines.scrollHandler(); }

		/* global hash_get */
		const hash_feed_id = hash_get('f');
		const hash_feed_is_cat = hash_get('c') == "1";

		if (hash_feed_id != undefined) {
			this.open({feed: hash_feed_id, is_cat: hash_feed_is_cat});
		} else {
			this.open({feed: -3});
		}

		this.hideOrShowFeeds(App.getInitParam("hide_read_feeds"));

		if (App.getInitParam("is_default_pw")) {
			console.warn("user password is at default value");

			if (dijit.byId("defaultPasswordDlg"))
				dijit.byId("defaultPasswordDlg").destroyRecursive();

			xhrPost("backend.php", {op: 'dlg', method: 'defaultpasswordwarning'}, (transport) => {
				const dialog = new dijit.Dialog({
					title: __("Your password is at default value"),
					content: transport.responseText,
					id: 'defaultPasswordDlg',
					style: "width: 600px",
					onCancel: function () {
						return true;
					},
					onExecute: function () {
						return true;
					},
					onClose: function () {
						return true;
					}
				});

				dialog.show();
			});
		}

		// bw_limit disables timeout() so we request initial counters separately
		if (App.getInitParam("bw_limit")) {
			this.requestCounters(true);
		} else {
			setTimeout(() => {
				this.requestCounters(true);
				setInterval(() => { this.requestCounters(); }, 60 * 1000)
			}, 250);
		}
	},
	activeIsCat: function() {
		return !!this._active_feed_is_cat;
	},
	getActive: function() {
		return this._active_feed_id;
	},
	setActive: function(id, is_cat) {
		console.log('setActive', id, is_cat);

		/* global hash_set */
		hash_set('f', id);
		hash_set('c', is_cat ? 1 : 0);

		this._active_feed_id = id;
		this._active_feed_is_cat = is_cat;

		$("headlines-frame").setAttribute("feed-id", id);
		$("headlines-frame").setAttribute("is-cat", is_cat ? 1 : 0);

		this.select(id, is_cat);

		PluginHost.run(PluginHost.HOOK_FEED_SET_ACTIVE, [this._active_feed_id, this._active_feed_is_cat]);
	},
	select: function(feed, is_cat) {
		const tree = dijit.byId("feedTree");

		if (tree) return tree.selectFeed(feed, is_cat);
	},
	toggleUnread: function() {
		const hide = !App.getInitParam("hide_read_feeds");

		xhrPost("backend.php", {op: "rpc", method: "setpref", key: "HIDE_READ_FEEDS", value: hide}, () => {
			this.hideOrShowFeeds(hide);
			App.setInitParam("hide_read_feeds", hide);
		});
	},
	hideOrShowFeeds: function (hide) {
		/*const tree = dijit.byId("feedTree");

		if (tree)
			return tree.hideRead(hide, App.getInitParam("hide_read_shows_special"));*/

		$$("body")[0].setAttribute("hide-read-feeds", !!hide);
		$$("body")[0].setAttribute("hide-read-shows-special", !!App.getInitParam("hide_read_shows_special"));
	},
	open: function(params) {
		const feed = params.feed;
		const is_cat = !!params.is_cat || false;
		const offset = params.offset || 0;
		const viewfeed_debug = params.viewfeed_debug;
		const append = params.append || false;
		const method = params.method;
		// this is used to quickly switch between feeds, sets active but xhr is on a timeout
		const delayed = params.delayed || false;

		if (offset != 0) {
			if (this.infscroll_in_progress)
				return;

			this.infscroll_in_progress = 1;

			window.clearTimeout(this._infscroll_timeout);
			this._infscroll_timeout = window.setTimeout(() => {
				console.log('infscroll request timed out, aborting');
				this.infscroll_in_progress = 0;

				// call scroll handler to maybe repeat infscroll request
				Headlines.scrollHandler();
			}, 10 * 1000);
		}

		Form.enable("toolbar-main");

		let query = Object.assign({op: "feeds", method: "view", feed: feed},
			dojo.formToObject("toolbar-main"));

		if (method) query.m = method;

		if (offset > 0) {
			if (Headlines.current_first_id) {
				query.fid = Headlines.current_first_id;
			}
		}

		if (this._search_query) {
			query = Object.assign(query, this._search_query);
		}

		if (offset != 0) {
			query.skip = offset;
		} else if (!is_cat && feed == this.getActive() && !params.method) {
			query.m = "ForceUpdate";
		}

		Form.enable("toolbar-main");

		if (!delayed)
			if (!this.setExpando(feed, is_cat,
				(is_cat) ? 'images/indicator_tiny.gif' : 'images/indicator_white.gif'))
				Notify.progress("Loading, please wait...", true);

		query.cat = is_cat;

		this.setActive(feed, is_cat);

		if (viewfeed_debug) {
			window.open("backend.php?" +
				dojo.objectToQuery(
					Object.assign({csrf_token: App.getInitParam("csrf_token")}, query)
				));
		}

		window.clearTimeout(this._viewfeed_wait_timeout);
		this._viewfeed_wait_timeout = window.setTimeout(() => {
			xhrPost("backend.php", query, (transport) => {
				try {
					window.clearTimeout(this._infscroll_timeout);
					this.setExpando(feed, is_cat, 'images/blank_icon.gif');
					Headlines.onLoaded(transport, offset, append);
					PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
				} catch (e) {
					App.Error.report(e);
				}
			});
		}, delayed ? 250 : 0);
	},
	catchupAll: function() {
		const str = __("Mark all articles as read?");

		if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {

			Notify.progress("Marking all feeds as read...");

			xhrPost("backend.php", {op: "feeds", method: "catchupAll"}, () => {
				this.requestCounters(true);
				this.reloadCurrent();
			});

			App.global_unread = 0;
			App.updateTitle();
		}
	},
	catchupFeed: function(feed, is_cat, mode) {
		is_cat = is_cat || false;

		let str = false;

		switch (mode) {
			case "1day":
				str = __("Mark %w in %s older than 1 day as read?");
				break;
			case "1week":
				str = __("Mark %w in %s older than 1 week as read?");
				break;
			case "2week":
				str = __("Mark %w in %s older than 2 weeks as read?");
				break;
			default:
				str = __("Mark %w in %s as read?");
		}

		const mark_what = this.last_search_query && this.last_search_query[0] ? __("search results") : __("all articles");
		const fn = this.getName(feed, is_cat);

		str = str.replace("%s", fn)
			.replace("%w", mark_what);

		if (App.getInitParam("confirm_feed_catchup") && !confirm(str)) {
			return;
		}

		const catchup_query = {
			op: 'rpc', method: 'catchupFeed', feed_id: feed,
			is_cat: is_cat, mode: mode, search_query: this.last_search_query[0],
			search_lang: this.last_search_query[1]
		};

		Notify.progress("Loading, please wait...", true);

		xhrPost("backend.php", catchup_query, (transport) => {
			App.handleRpcJson(transport);

			const show_next_feed = App.getInitParam("on_catchup_show_next_feed");

			// only select next unread feed if catching up entirely (as opposed to last week etc)
			if (show_next_feed && !mode) {
				const nuf = this.getNextUnread(feed, is_cat);

				if (nuf) {
					this.open({feed: nuf, is_cat: is_cat});
				}
			} else if (feed == this.getActive() && is_cat == this.activeIsCat()) {
				this.reloadCurrent();
			}

			Notify.close();
		});
	},
	catchupCurrent: function(mode) {
		this.catchupFeed(this.getActive(), this.activeIsCat(), mode);
	},
	catchupFeedInGroup: function(id) {
		const title = this.getName(id);

		const str = __("Mark all articles in %s as read?").replace("%s", title);

		if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {

			const rows = $$("#headlines-frame > div[id*=RROW][class*=Unread][data-orig-feed-id='" + id + "']");

			rows.each((row) => {
				row.removeClassName("Unread");
			})
		}
	},
	getUnread: function(feed, is_cat) {
		try {
			const tree = dijit.byId("feedTree");

			if (tree && tree.model)
				return tree.model.getFeedUnread(feed, is_cat);

		} catch (e) {
			//
		}

		return -1;
	},
	getCategory: function(feed) {
		try {
			const tree = dijit.byId("feedTree");

			if (tree && tree.model)
				return tree.getFeedCategory(feed);

		} catch (e) {
			//
		}

		return false;
	},
	getName: function(feed, is_cat) {
		if (isNaN(feed)) return feed; // it's a tag

		const tree = dijit.byId("feedTree");

		if (tree && tree.model)
			return tree.model.getFeedValue(feed, is_cat, 'name');
	},
	setUnread: function(feed, is_cat, unread) {
		const tree = dijit.byId("feedTree");

		if (tree && tree.model)
			return tree.model.setFeedUnread(feed, is_cat, unread);
	},
	setValue: function(feed, is_cat, key, value) {
		try {
			const tree = dijit.byId("feedTree");

			if (tree && tree.model)
				return tree.model.setFeedValue(feed, is_cat, key, value);

		} catch (e) {
			//
		}
	},
	getValue: function(feed, is_cat, key) {
		try {
			const tree = dijit.byId("feedTree");

			if (tree && tree.model)
				return tree.model.getFeedValue(feed, is_cat, key);

		} catch (e) {
			//
		}
		return '';
	},
	setIcon: function(feed, is_cat, src) {
		const tree = dijit.byId("feedTree");

		if (tree) return tree.setFeedIcon(feed, is_cat, src);
	},
	setExpando: function(feed, is_cat, src) {
		const tree = dijit.byId("feedTree");

		if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);

		return false;
	},
	getNextUnread: function(feed, is_cat) {
		const tree = dijit.byId("feedTree");
		const nuf = tree.model.getNextUnreadFeed(feed, is_cat);

		if (nuf)
			return tree.model.store.getValue(nuf, 'bare_id');
	},
	search: function() {
		if (dijit.byId("searchDlg"))
			dijit.byId("searchDlg").destroyRecursive();

		xhrPost("backend.php",
					{op: "feeds", method: "search",
						param: Feeds.getActive() + ":" + Feeds.activeIsCat()},
					(transport) => {

						const dialog = new dijit.Dialog({
							id: "searchDlg",
							content: transport.responseText,
							title: __("Search"),
							style: "width: 600px",
							execute: function () {
								if (this.validate()) {
									Feeds._search_query = this.attr('value');

									// disallow empty queries
									if (!Feeds._search_query.query)
										Feeds._search_query = false;

									this.hide();
									Feeds.reloadCurrent();
								}
							},
						});

						const tmph = dojo.connect(dialog, 'onShow', function () {
							dojo.disconnect(tmph);

							if (Feeds._search_query) {
								if (Feeds._search_query.query)
									dijit.byId('search_query')
										.attr('value', Feeds._search_query.query);

								if (Feeds._search_query.search_language)
									dijit.byId('search_language')
										.attr('value', Feeds._search_query.search_language);
							}

						});

						dialog.show();
					});

	},
	updateRandom: function() {
		console.log("in update_random_feed");

		xhrPost("backend.php", {op: "rpc", method: "updaterandomfeed"}, (transport) => {
			App.handleRpcJson(transport, true);
		});
	},
};
