import './nav.css';
import utils from 'somes';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ViewController } from '../lib/ctr';
import error from '../lib/errno_handles';
import { EventNoticer } from 'somes/event';
var loading = '正在载入数据..';
class PrivPage extends ViewController {
    constructor(props) {
        super(props);
        this.m_prev = null;
        this.m_next = null;
        this.m_status = -1;
        this.m_index = 0;
        this._count = 0;
        this.state = { component: null };
        this.m_props = props;
        this.m_index = props.index;
        this.m_panel = props.panel;
    }
    async loader() {
        try {
            if (this.m_props.notFound) {
                this.setState({ component: this.m_props.notFound });
            }
            else {
                var route = this.m_props.route;
                this._count++;
                var com = (await route.page()).default;
                if (this.state.component === com) {
                    this.setState({ component: null });
                }
                this.setState({ component: com, load_count: this._count });
            }
        }
        catch (e) {
            error(e);
        }
    }
    get status() {
        return this.m_status;
    }
    get url() {
        return this.m_props.url;
    }
    get nav() {
        return this.m_props.nav;
    }
    get pathname() {
        return this.m_props.pathname;
    }
    get params() {
        return this.m_props.params;
    }
    get index() {
        return this.m_index;
    }
    triggerMounted() {
        this.loader();
    }
    onShow(data = {}) {
        try {
            this.refs.self.triggerShow(data);
        }
        catch (err) {
            console.error(err);
        }
    }
    onHide() {
        try {
            this.refs.self.triggerHide();
        }
        catch (err) {
            console.error(err);
        }
    }
    unmount() {
        ReactDom.unmountComponentAtNode(this.m_panel);
        this.m_panel.parentNode.removeChild(this.m_panel);
    }
    replace(props) {
        this.m_props = {
            ...props,
            index: this.m_index,
            panel: this.m_panel,
        };
        this.props = this.m_props;
        this.loader();
    }
    render() {
        var Com = this.state.component;
        if (Com) {
            var props = {
                url: this.m_props.url,
                pathname: this.m_props.pathname,
                params: this.m_props.params,
                ref: 'self',
                priv: this,
            };
            return (React.createElement(Com, Object.assign({}, props)));
        }
        else {
            return (React.createElement("div", { className: "init-loading" },
                " ",
                loading,
                " "));
        }
    }
    getStyle(styleStr) {
        return `
			width: 100%;
			min-height: 100%;
			background: #fff;
			position: absolute;
			z-index: ${this.m_index};
			` + styleStr;
    }
    intoBackground(time) {
        if (this.m_next == null)
            return;
        clearTimeout(this.m_timeout);
        if (this.m_status != 1) {
            if (time) {
                requestAnimationFrame(e => {
                    requestAnimationFrame(e => {
                        this.m_panel.style.cssText = this.getStyle(`
							display: block;
							transform: translateX(-35vw) translateZ(1px);
							transition-property: transform;
							transition-duration: ${time}ms;
						`);
                        this.m_timeout = setTimeout(e => {
                            this.m_panel.style.transitionProperty = 'none';
                            this.m_panel.style.display = 'none';
                        }, time + 200);
                    });
                });
            }
            else {
                this.m_panel.style.cssText = this.getStyle(`
					transform: translateX(-50vw);
					transition-property: none;
				`);
            }
        }
        this.m_status = 1;
        this.onHide();
    }
    intoForeground(time, data = {}) {
        if (this.m_status == 0)
            return;
        this.m_next = null;
        clearTimeout(this.m_timeout);
        if (this.m_status == -1) {
            if (time && this.m_prev) {
                this.m_panel.style.cssText = this.getStyle(`
					display: block;
					transform: translateX(100vw);
				`);
                requestAnimationFrame(e => {
                    requestAnimationFrame(e => {
                        this.m_panel.style.cssText = this.getStyle(`
							transform: translateX(0) translateZ(1px);
							transition-property: transform;
							transition-duration: ${time}ms;
							box-shadow: -1px 0 2px #aaa;
						`);
                        this.m_timeout = setTimeout(e => {
                            this.m_panel.style.transitionProperty = 'none';
                            this.m_panel.style.boxShadow = 'none';
                            this.m_panel.style.transform = 'none';
                            this.m_panel.style.boxShadow = 'none';
                        }, time + 200);
                    });
                });
            }
            else {
                this.m_panel.style.cssText = this.getStyle(`
					transform: translateX(0); 
					display: block; 
					transition-property: none;
					border-left: none;
				`);
            }
            this.m_status = 0;
        }
        else if (this.m_status == 1) {
            if (time) {
                this.m_panel.style.cssText = this.getStyle(`
					display: block;
					transform: translateX(-35vw);
				`);
                requestAnimationFrame(e => {
                    requestAnimationFrame(e => {
                        this.m_panel.style.cssText = this.getStyle(`
							display: block;
							transform: translateX(0) translateZ(1px);
							transition-property: transform;
							transition-duration: ${time}ms;
							border-left: none;
						`);
                        this.m_timeout = setTimeout(e => {
                            this.m_panel.style.transitionProperty = 'none';
                            this.m_panel.style.transform = 'none';
                        }, time + 200);
                    });
                });
            }
            else {
                this.m_panel.style.cssText = this.getStyle(`
					transform: none; 
					display: block; 
					transition-property: none;
					border-left: none;
				`);
            }
            this.m_status = 0;
            this.onShow(data);
        }
    }
    intoLeave(time) {
        if (this.m_status == 0) {
            clearTimeout(this.m_timeout);
            if (time) {
                this.m_panel.style.cssText = this.getStyle(`
					display: block;
					transform: translateX(100vw) translateZ(1px);
					transition-property: transform;
					transition-duration: ${time}ms;
					box-shadow: -1px 0 2px #aaa;
				`);
                this.m_timeout = setTimeout(e => {
                    this.unmount();
                }, time + 200);
                this.m_status = -1;
                return;
            }
        }
        this.m_status = -1;
        this.unmount();
    }
}
export class Nav extends ViewController {
    constructor() {
        super(...arguments);
        this.m_pages = [];
        this.m_current = null;
        this.m_routes = {};
        this.m_animating = false;
        this.onNav = new EventNoticer('Nav', this);
        this.onEnd = new EventNoticer('End', this);
    }
    get _mcls() {
        var cls_1 = '_main ';
        if (utils.debug) {
            cls_1 += '_test ';
        }
        if (Nav.platform == 'android') {
            cls_1 += '_android ';
        }
        else if (Nav.platform == 'iphonex') {
            cls_1 += '_iphonex ';
        }
        else if (Nav.platform == 'iphone') {
            cls_1 += '_iphone ';
        }
        return cls_1;
    }
    triggerNav(data) {
        if (this.props.onNav) {
            this.props.onNav(data);
        }
        this.onNav.trigger(data);
    }
    triggerEnd() {
        if (this.props.onEnd) {
            this.props.onEnd();
        }
        this.onEnd.trigger();
    }
    triggerMounted() {
        var routes = this.props.routes;
        routes.forEach(e => {
            if (typeof e.path == 'string') {
                e.path = [e.path];
            }
            for (var url of e.path) {
                url = url[0] != '/' ? '/' + url : url;
                this.m_routes[url] = e;
            }
        });
        this.push(this.props.initURL || '/', false);
    }
    get length() {
        return this.m_pages.length;
    }
    getPage(index) {
        return this.m_pages[index].refs.self;
    }
    get routes() {
        return this.m_routes;
    }
    m_parseProps(args) {
        if (typeof args == 'string') {
            args = { url: args };
        }
        var { url, params = {} } = args;
        url = url[0] != '/' ? '/' + url : url;
        var pathname = url;
        var index = url.indexOf('?');
        if (index != -1) {
            url.substr(index + 1).split('&').forEach(e => {
                if (e) {
                    var ls = e.split('=');
                    params[ls[0]] = ls[1] || '';
                }
            });
            pathname = url.substring(0, index);
        }
        var route = this.m_routes[pathname];
        var props = {
            nav: this,
            url: url,
            pathname: pathname,
            params: params,
            route: route,
        };
        if (!route) {
            if (this.props.notFound) {
                props.notFound = this.props.notFound;
            }
            else {
                throw new Error(`Not found ${url}`);
            }
        }
        return props;
    }
    m_push(url, animate, index, cb) {
        if (this.m_animating && animate)
            return false;
        var props = this.m_parseProps(url);
        var panel = document.createElement('div');
        this.refs.root.appendChild(panel);
        panel.className = this._mcls;
        var self = this;
        var prev = this.m_current;
        var el = React.createElement(PrivPage, Object.assign({}, props, { index: index, panel: panel }));
        ReactDom.render(el, panel, function () {
            var page = this;
            self.m_current = page;
            self.m_pages.push(page);
            page.m_prev = prev;
            if (prev) {
                prev.m_next = page;
            }
            var animateNum = animate ? 400 : 0;
            if (animate) {
                self.m_animating = true;
                setTimeout(e => self.m_animating = false, animateNum);
            }
            if (prev) {
                prev.intoBackground(animateNum);
            }
            page.intoForeground(animateNum, { active: 'push' });
            var { pathname, params } = props;
            self.triggerNav({ action: 'push', pathname, params, count: 1 });
            if (cb)
                cb(page);
        });
        return true;
    }
    push(url, animate = true) {
        return this.m_push(url, animate, this.length);
    }
    pops(result, index, animate = true) {
        if (this.m_animating && animate)
            return false;
        if (this.length == 1 && index <= -1) {
            this.triggerEnd();
            return false;
        }
        index = Math.max(0, index);
        if (index >= this.length - 1)
            return false;
        var page = this.m_pages[index];
        var arr = this.m_pages.splice(index + 1);
        var next = arr.pop();
        arr.forEach(function (page) {
            page.intoLeave(0);
        });
        this.m_current = page;
        var animateNum = animate ? 400 : 0;
        if (animate) {
            this.m_animating = true;
            setTimeout(e => this.m_animating = false, animateNum);
        }
        page.m_next = null;
        next.m_prev = null;
        page.intoForeground(animateNum, { ...result, active: 'pop' });
        next.intoLeave(animateNum);
        this.triggerNav({ action: 'pop', pathname: page.pathname, params: page.params, count: arr.length + 1 });
        return true;
    }
    pop(animate = true, result = {}) {
        return this.pops(result, this.length - 2, animate);
    }
    replace(url, animate = false, index = -1) {
        if (index >= 0 && index < this.length - 1) {
            if (!this.pops({}, index, animate))
                return false;
        }
        else if (animate) {
            var cur = this.m_current;
            if (!cur)
                return false;
            utils.assert(this.length > 0);
            return this.m_push(url, animate, this.length - 1, page => {
                setTimeout(e => {
                    cur.intoLeave(0);
                }, 400);
                var prev = cur.m_prev;
                if (prev) {
                    prev.m_next = page;
                }
                page.m_prev = prev;
                this.m_pages.deleteOf(cur);
                this.triggerNav({ action: 'replace', pathname: page.pathname, params: page.params, count: 0 });
            });
        }
        var props = this.m_parseProps(url);
        if (this.m_current) {
            this.m_current.replace(props);
            this.triggerNav({ action: 'replace', pathname: props.pathname, params: props.params, count: 0 });
        }
        return true;
    }
    get current() {
        utils.assert(this.m_current);
        return this.m_current.refs.self;
    }
    render() {
        return (React.createElement("div", { className: "_root", ref: "root" }));
    }
}
Nav.platform = '';
export class NavPage extends ViewController {
    get nav() {
        return this.props.priv.nav;
    }
    get url() {
        return this.props.url;
    }
    get pathname() {
        return this.props.pathname;
    }
    get index() {
        return this.props.priv.index;
    }
    get params() {
        return this.props.params;
    }
    async triggerLoad() {
        if (this.props.priv.status == 0) {
            this.triggerShow({ active: 'init' });
        }
    }
    triggerRemove() {
        if (this.props.priv.status == -1)
            this.triggerHide();
    }
    triggerShow(data = {}) {
    }
    triggerHide() {
    }
    pushPage(url, animate = true) {
        return this.nav.push(url, animate);
    }
    popPage(animate = true, result = {}) {
        return this.nav.pop(animate, result);
    }
    replacePage(url, animate = false, index = -1) {
        return this.nav.replace(url, animate, index);
    }
}
