import { ChangeDetectorRef, Component, ComponentFactoryResolver, HostListener, NgZone, OnDestroy, OnInit, Renderer, ViewChild, ViewContainerRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Message } from 'primeng/primeng';

import { Subscription } from 'rxjs/Subscription';

import { ConfigService } from './../../services/config.service';
import { MenuService } from './../../services/menu.service';
import { MsgsService } from './../../services/msgs.service';
import { UtilsService } from './../../services/utils.service';


@Component({
    selector: 'app-dashboard',
    templateUrl: './full-layout.component.html',
    styleUrls: ['./full-layout.component.scss']
})
export class FullLayoutComponent implements OnInit, OnDestroy {

    menuClick: boolean;

    menuButtonClick: boolean;

    topbarMenuButtonClick: boolean;

    topbarMenuClick: boolean;

    topbarMenuActive: boolean;

    activeTopbarItem: Element;

    layoutMode = 'horizontal';  //'overlay';    

    sidebarActive: boolean;

    mobileMenuActive: boolean;

    darkMenu: boolean;

    isRTL: boolean;

    rippleInitListener: any;

    rippleMouseDownListener: any;

    menuHoverActive: boolean;

    resetMenu: boolean;

    subscriptions: Array<Subscription> = [];
    errorMsgs: Message[] = [];
    successMsgs: Message[] = [];
    showAllErrorsCalled: boolean = false;
    dialogOpen: boolean = false;

    @ViewChild('customHeader', { read: ViewContainerRef }) headerContainerRef: ViewContainerRef;
    @ViewChild('customFooter', { read: ViewContainerRef }) footerContainerRef: ViewContainerRef;

    showDefaultHeader: boolean = true;
    showDefaultFooter: boolean = true;
    showMenu: boolean = true;
    showFeedback: boolean = true;
    customHeader: boolean = false;

    constructor(
        public renderer: Renderer,
        public zone: NgZone,
        private utilsService: UtilsService,
        public menuService: MenuService,
        public msgsService: MsgsService,
        private activatedRoute: ActivatedRoute,
        private factoryResolver: ComponentFactoryResolver,
        private configService: ConfigService,
        private cdRef : ChangeDetectorRef
    ) {

    }

    addDynamicComponent(dynamicComponent, viewContainerRef: ViewContainerRef) {
        const factory = this.factoryResolver.resolveComponentFactory(dynamicComponent)
        const component = factory.create(viewContainerRef.parentInjector);
        viewContainerRef.insert(component.hostView)
    }

    ngOnInit(): void {
        this.activatedRoute.data.subscribe(
            data => {
                if (data['showDefaultHeader'] != null) {
                    this.showDefaultHeader = data['showDefaultHeader'];
                }
                if (data['showDefaultFooter'] != null) {
                    this.showDefaultFooter = data['showDefaultFooter'];
                }
                if (data['showMenu'] != null) {
                    this.showMenu = data['showMenu'];
                }
                if (data['showFeedback'] != null) {
                    this.showFeedback = data['showFeedback'];
                }
                if (data['customHeader']) {
                    this.customHeader = true;
                    this.addDynamicComponent(data['customHeader'], this.headerContainerRef);
                }
                if (data['customFooter']) {
                    this.addDynamicComponent(data['customFooter'], this.footerContainerRef);
                }
            }
        );
        this.zone.runOutsideAngular(() => { this.bindRipple(); });
        this.subscriptions.push(
            this.msgsService.successMsgsUpdated.subscribe(
                data => {
                    this.successMsgs = data;
                }
            )
        );

        this.subscriptions.push(
            this.msgsService.errorMsgsUpdated.subscribe(
                data => {
                    this.errorMsgs = data;
                }
            )
        );

        this.subscriptions.push(
            this.msgsService.showAllErrors.subscribe((data) => {
                this.showAllErrorsCalled = data;
            })
        );
    }

    onRouteUpdate() {
        this.menuService.reloadMenuData(this.subscriptions);
        this.msgsService.clearErrorMessages();
    }

    bindRipple() {
        this.rippleInitListener = this.init.bind(this);
        document.addEventListener('DOMContentLoaded', this.rippleInitListener);
    }

    init() {
        this.rippleMouseDownListener = this.rippleMouseDown.bind(this);
        document.addEventListener('mousedown', this.rippleMouseDownListener, false);
    }

    rippleMouseDown(e) {
        for (let target = e.target; target && target !== this; target = target['parentNode']) {
            if (!this.isVisible(target)) {
                continue;
            }

            // Element.matches() -> https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
            if (this.selectorMatches(target, '.ripplelink, .ui-button')) {
                const element = target;
                this.rippleEffect(element, e);
                break;
            }
        }
    }

    selectorMatches(el, selector) {
        const p = Element.prototype;
        const f = p['matches'] || p['webkitMatchesSelector'] || p['mozMatchesSelector'] || p['msMatchesSelector'] || function (s) {
            return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
        };
        return f.call(el, selector);
    }

    isVisible(el) {
        return !!(el.offsetWidth || el.offsetHeight);
    }

    rippleEffect(element, e) {
        if (element.querySelector('.ink') === null) {
            const inkEl = document.createElement('span');
            this.addClass(inkEl, 'ink');

            if (this.hasClass(element, 'ripplelink') && element.querySelector('span')) {
                element.querySelector('span').insertAdjacentHTML('afterend', '<span class=\'ink\'></span>');
            } else {
                element.appendChild(inkEl);
            }
        }

        const ink = element.querySelector('.ink');
        this.removeClass(ink, 'ripple-animate');

        if (!ink.offsetHeight && !ink.offsetWidth) {
            const d = Math.max(element.offsetWidth, element.offsetHeight);
            ink.style.height = d + 'px';
            ink.style.width = d + 'px';
        }

        const x = e.pageX - this.getOffset(element).left - (ink.offsetWidth / 2);
        const y = e.pageY - this.getOffset(element).top - (ink.offsetHeight / 2);

        ink.style.top = y + 'px';
        ink.style.left = x + 'px';
        ink.style.pointerEvents = 'none';
        this.addClass(ink, 'ripple-animate');
    }

    hasClass(element, className) {
        if (element.classList) {
            return element.classList.contains(className);
        } else {
            return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
        }
    }

    addClass(element, className) {
        if (element.classList) {
            element.classList.add(className);
        } else {
            element.className += ' ' + className;
        }
    }

    removeClass(element, className) {
        if (element.classList) {
            element.classList.remove(className);
        } else {
            element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
        }
    }

    getOffset(el) {
        const rect = el.getBoundingClientRect();

        return {
            top: rect.top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0),
            left: rect.left + (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0),
        };
    }

    unbindRipple() {
        if (this.rippleInitListener) {
            document.removeEventListener('DOMContentLoaded', this.rippleInitListener);
        }
        if (this.rippleMouseDownListener) {
            document.removeEventListener('mousedown', this.rippleMouseDownListener);
        }
    }

    ngOnDestroy() {
        this.unbindRipple();
        this.utilsService.unsubscribeSubscriptions(this.subscriptions);
    }

    onWrapperClick() {
        if (!this.menuClick && !this.menuButtonClick) {
            this.mobileMenuActive = false;
        }

        if (!this.topbarMenuClick && !this.topbarMenuButtonClick) {
            this.topbarMenuActive = false;
            this.activeTopbarItem = null;
        }

        if (!this.menuClick) {
            if (this.isHorizontal() || this.isOverlay()) {
                this.resetMenu = true;
            }

            this.menuHoverActive = false;
        }


        this.menuClick = false;
        this.menuButtonClick = false;
        this.topbarMenuClick = false;
        this.topbarMenuButtonClick = false;
    }

    onMenuButtonClick(event: Event) {
        this.menuButtonClick = true;

        if (this.isMobile()) {
            this.mobileMenuActive = !this.mobileMenuActive;
        }

        event.preventDefault();
    }

    onTopbarMobileMenuButtonClick(event: Event) {
        this.topbarMenuButtonClick = true;
        this.topbarMenuActive = !this.topbarMenuActive;
        event.preventDefault();
    }

    onTopbarRootItemClick(event: Event, item: Element) {
        if (this.activeTopbarItem === item) {
            this.activeTopbarItem = null;
        } else {
            this.activeTopbarItem = item;
        }

        //event.preventDefault();       //Commented so that top menu links work properly
    }

    onTopbarMenuClick(event: Event) {
        this.topbarMenuClick = true;
    }

    onSidebarClick(event: Event) {
        this.menuClick = true;
        this.resetMenu = false;
    }

    onToggleMenuClick(event: Event) {
        this.layoutMode = this.layoutMode !== 'static' ? 'static' : 'overlay';
        event.preventDefault();
    }

    isMobile() {
        return window.innerWidth <= this.configService.settings.mobileBreakpoint;
    }

    isTablet() {
        const width = window.innerWidth;
        return width <= this.configService.settings.mobileBreakpoint && width > 640;
    }

    isHorizontal() {
        return this.layoutMode === 'horizontal';
    }

    isOverlay() {
        return this.layoutMode === 'overlay';
    }

    @HostListener('window:resize', ['$event'])
    onResize(event) {
        this.cdRef.detectChanges();
    }
}