import React from 'react';
import {Node, Link, Graph} from '../helpers/graph'
import {TreeNode, Tree} from '../helpers/tree'
import ViewSystem from './ViewSystem';

import BaseSystem from './System';

import CSS from 'css';

function log(...m) {
	console.log(...m);
}

const MATCH_NODE = / *([a-zA-Z-_*]+) */gm;
const MATCH_CHILD = / *> */gm;
const MATCH_SPACES = / +/gm;
const MATCH_PLUS = / *\+ */gm;
const MATCH_MINUS = / *\- */gm;
export default class RulingSystem extends BaseSystem {
	constructor() {
		super();

		this.rules = [];
		this.index = {};
	}


	getDeclarations(rule) {
		let res = rule.declarations.reduce((acc, curr) => {
			return {
				...acc,
				[curr.property]: curr.value
			}
		}, {});

		return res;
	}

	getCSS(Node, View) {
		let { 
			rules,
			contentrules
		} = this.match(Node,View);
		let css = rules.map(r => this.getDeclarations(r))
		let main = css.reduce((acc, curr) => {
			return {
				...acc,
				...curr
			}
		}, {});
		let contentcss = contentrules.map(r => this.getDeclarations(r))
		let content = contentcss.reduce((acc, curr) => {
			return {
				...acc,
				...curr
			}
		}, {});

		return {
			rules: main,
			contentrules: content
		};
	}
	match(Node, View) {
		let rules = [];
		// ALL CHECK
		// for(var i in this.rules) {
		// 	let rule = this.rules[i];
		// 	if(this.matchRule(rule, Node, View)) {
		// 		rules.push(rule);
		// 	}
		// }

		if(!Node.content)return [];
		// Index
		let array = [
			...(this.index['*'] || []), 
			...(this.index[Node.content.value] || [])
		];

		for(var i in array) {
			let rule = array[i];
			if (this.matchRule(rule, Node, View)) {
				rules.push(rule);
			}
		}

		let contentrules = [];
		let contentarray = [
			...(this.index['~*'] || []), 
			...(this.index['~'+Node.content.value] || [])
		];
		for(var i in contentarray) {
			let rule = contentarray[i];
			if (this.matchRule(rule, Node, View, "~")) {
				contentrules.push(rule);
			}
		}

		return {
			rules,
			contentrules
		};
	}

	matchRule(rule, Node, View, prefix) {
		let {
			selectors,
			declarations
		} = rule;
		
		for (let i in selectors) {
			let selector = selectors[i];
			if (this.matchSelector(selector, Node, View, prefix)) {
				return true;
			}
		}

		return false;
	}

	matchSelector(selector, Node, View, prefix = "") {
		if((Node.depth+1) < selector.length) return false;
		for (let i = selector.length-1; i >= 0; i--) {
			let ViewNode = Node.content;
			let {
				nodes, 
				prenodes,
				nextnodes
			} = selector[i];
			if(View.isRoot(Node) && nodes.includes('ROOT')) return true;
			if(!Node.content)return false;

			if(!nodes.includes(prefix+ViewNode.value) && !nodes.includes(prefix+'*')){
				return false;
			}
			prefix = "";

			if(prenodes.length > 0) {
				let preNode = View.getBefore(Node);
				let preNodeValue = preNode && preNode.content && preNode.content.value;
				if(preNodeValue && !prenodes.includes(preNodeValue)){
					return false;
				}
			}
			if(nextnodes.length > 0) {
				let afterNode = View.getAfter(Node);
				let afterNodeValue = afterNode && afterNode.content && afterNode.content.value;
				if(afterNodeValue && !nextnodes.includes(afterNodeValue)){
					return false;
				}
			}
			Node = View.getParent(Node);
		}
		return true;
	}

	parseSelector(selector) {
		let string = selector;
		let tree = string.split(MATCH_CHILD);
		for (let i in tree) {
			
			let minus = tree[i].split(MATCH_MINUS);
			if(minus.length === 1) {
				minus[1] = minus[0];
				minus[0] = "";
			}
			let plus = minus[1].split(MATCH_PLUS);
			if(plus.length === 1) {
				plus[1] = "";
			}
			let nodes = plus[0].split(MATCH_SPACES).filter(Boolean);
			let prenodes = minus[0].split(MATCH_SPACES).filter(Boolean);
			let nextnodes = plus[1].split(MATCH_SPACES).filter(Boolean);
			tree[i] = {
				nodes,
				prenodes,
				nextnodes,
				initial: tree[i]
			}
		}
		return tree;
	}

	addRule(rule) {
		let {
			selectors,
			declarations
		} = rule;
		let parsed = selectors.map(s => this.parseSelector(s))
		let res = {
			selectors: parsed,
			declarations
		}
		this.rules.push(res);
		parsed.forEach(selectorGroup => {
			selectorGroup.forEach(selector => { 
				selector.nodes.forEach(node => {
					if(!this.index[node])this.index[node] = [];
					this.index[node].push(res);
				})
			})
		});
	}

	addRuleFile(file){
		let ruleCSS = CSS.parse(file);
		console.log("RULECSS", ruleCSS);
		for(var i in ruleCSS.stylesheet.rules) {
			this.addRule(ruleCSS.stylesheet.rules[i]);
		}
		this.forceUpdate();
	}

	export() {
		return {};
	}

	import(data) {
		return this;
	}
}