/**
 * This file is part of Anis Client.
 *
 * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';

import { nanValidator, rangeValidator } from '../../validators';
import { ConeSearch, Resolver } from 'src/app/instance/store/models';

@Component({
    selector: 'app-dec',
    templateUrl: 'dec.component.html',
    styleUrls: ['input-group.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
/**
 * @class
 * @classdesc DEC component.
 */
export class DecComponent {
    /**
     * Disables DEC fields.
     *
     * @param  {boolean} disabled - If the field has to be disabled.
     */
    @Input()
    set disabled(disabled: boolean) {
        this.isDisabled = disabled;
        this.initFields();
    }
    /**
     * Sets RA, DEC and radius from cone search.
     *
     * @param  {ConeSearch} coneSearch - The cone search.
     */
    @Input()
    set coneSearch(coneSearch: ConeSearch) {
        this.ra = coneSearch.ra;
        this.radius = coneSearch.radius;
        if (coneSearch.dec) {
            this.decDegree.setValue(coneSearch.dec);
            if(this.decDegree.valid && !this.decHFocused && !this.decMFocused && !this.decSFocused) {
                this.decDegree2HMS(coneSearch.dec);
            }
        } else {
            this.decDegree.reset();
            this.decH.reset();
            this.decM.reset();
            this.decS.reset();
        }
        this.initFields();
    }
    /**
     * Sets RA from resolver.
     *
     * @param  {Resolver} resolver - The resolver.
     */
    @Input()
    set resolver(resolver: Resolver) {
        this.resolvedDec = null;
        if (resolver) {
            this.resolvedDec = resolver.dec;
            this.decDegree.setValue(resolver.dec);
            this.decDegree2HMS(resolver.dec);
        }
    }
    /**
     * Sets isDegree.
     *
     * @param  {string} unit - The unit.
     */
    @Input()
    set unit(unit: string) {
        unit === 'degree' ? this.isDegree = true : this.isDegree = false;
        this.initFields();
    }
    @Output() updateConeSearch: EventEmitter<ConeSearch> = new EventEmitter();
    @Output() deleteResolver: EventEmitter<null> = new EventEmitter();

    ra: number;
    radius: number;
    isDisabled = false;
    isDegree = true;
    resolvedDec: number;
    decHFocused: boolean = false;
    decMFocused: boolean = false;
    decSFocused: boolean = false;

    decDegree = new FormControl('', [Validators.required, nanValidator, rangeValidator(-90, 90, 'DEC')]);
    decH = new FormControl('', [nanValidator, rangeValidator(-90, 90, 'Degree')]);
    decM = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Minutes')]);
    decS = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Seconds')]);

    /**
     * Sets DEC fields.
     */
    initFields(): void {
        if (this.isDisabled) {
            this.decDegree.disable();
            this.decH.disable();
            this.decM.disable();
            this.decS.disable();
        } else if (this.isDegree) {
            this.decDegree.enable();
            this.decH.disable();
            this.decM.disable();
            this.decS.disable();
        } else {
            this.decDegree.disable();
            this.decH.enable();
            this.decM.enable();
            this.decS.enable();
        }
    }

    /**
     * Converts DEC hour minute second from degree and sets DEC HMS fields.
     *
     * @param  {number} value - The degree value.
     */
    decDegree2HMS(value: number): void {
        const hh = Math.trunc(value);
        let tmp = (Math.abs(value - hh)) * 60;
        const mm = Math.trunc(tmp);
        tmp = (tmp - mm) * 60;
        const ss = tmp.toFixed(2);
        this.decH.setValue(hh);
        this.decM.setValue(mm);
        this.decS.setValue(ss);
    }

    /**
     * Sets DEC degree from hour minute second and sets DEC degree field.
     */
    decHMS2Degree(): void {
        const hh = +this.decH.value;
        const mm = +this.decM.value;
        const ss = +this.decS.value;
        const tmp = ((ss / 60) + mm) / 60;
        let deg = tmp + Math.abs(hh);
        if (hh < 0) {
            deg = -deg;
        }
        this.decDegree.setValue(+deg.toFixed(8));
    }

    /**
     * Changes fields focus.
     *
     * @param  {string} field - The field.
     * @param  {boolean} isFocused - Is the field is focused.
     */
    changeFocus(field: string, isFocused: boolean) {
        switch (field) {
            case 'dech':
                this.decHFocused = isFocused;
                break;
            case 'decm':
                this.decMFocused = isFocused;
                break
            case 'decs':
                this.decSFocused = isFocused;
                break;
        }
    }

    /**
     * Manages DEC value change.
     */
    decChange(): void {
        if (this.isDegree) {
            if (this.decDegree.valid) {
                this.decDegree2HMS(this.decDegree.value);
            } else {
                this.decH.reset();
                this.decM.reset();
                this.decS.reset();
            }
            this.updateConeSearch.emit({ ra: this.ra, dec: this.decDegree.value, radius: this.radius } as ConeSearch);
        } else {
            if (this.decH.valid && this.decM.valid && this.decS.valid) {
                this.setToDefaultValue();
                this.decHMS2Degree();
                this.updateConeSearch.emit({ ra: this.ra, dec: this.decDegree.value, radius: this.radius } as ConeSearch);
            } else {
                this.decDegree.reset();
            }
        }
        this.resetResolver();
    }

    /**
     * Sets DEC hour minute second fields to default value if not valid.
     */
    setToDefaultValue(): void {
        if (this.decH.value === '' || this.decH.value === null) {
            this.decH.setValue(0);
        }
        if (this.decM.value === '' || this.decM.value === null) {
            this.decM.setValue(0);
        }
        if (this.decS.value === '' || this.decS.value === null) {
            this.decS.setValue(0);
        }
    }

    /**
     * Emits reset resolver event.
     */
    resetResolver(): void {
        if (this.resolvedDec && this.resolvedDec !== this.decDegree.value) {
            this.deleteResolver.emit();
        }
    }
}