import { Pipe, PipeTransform } from '@angular/core';

/**
 * convert number to gps degrees minutes seconds format with units
 * 
 * Usage Latitude:
 *   value | gpsDms : 90
 *  return 41deg 23" 232'N 
 * Example Longitude:
 *   {{ '41.23' | gpsDms : 180 }}
 *  return 41deg 23" 232'E 
 */
@Pipe({ name: 'gpsDms' })
export class GpsDmsPipe implements PipeTransform {
    transform(value: number, type: CoordinateType): string {
        return dec2deg(value, type);
    }
}

export enum CoordinateType {
    LATITUDE = 90,
    LONGITUDE = 180,
}

export enum GeoSide {
    NORTH = 'N',
    SOUTH = 'S',
    EAST = 'E',
    WEST = 'W',
}
export const LATITUDE_REGEX = /^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,6})?))$/
export const LONGITUDE_REGEX = /^(\+|-)?(?:180(?:(?:\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\.[0-9]{1,6})?))$/

export function validateCoordinates(lat: string, lon: string) {
    return LATITUDE_REGEX.test(lat) && LONGITUDE_REGEX.test(lon);
}

export function dec2deg(value: number, type: CoordinateType): string {
    const CHAR_DEG = '\u00B0';
    const CHAR_MIN = '\u0027';
    const CHAR_SEC = '\u0022';
    const CHAR_SEP = '\u0020';
    const sign = value < 0 ? -1 : 1;

    const abs = Math.abs(Math.round(value * 1000000));

    if (abs > (type * 1000000)) {
        return NaN.toString();
    }

    const dec = abs % 1000000 / 1000000;
    const deg = Math.floor(abs / 1000000) * sign;
    const min = Math.floor(dec * 60);
    const sec = (dec - min / 60) * 3600;

    let result = '';

    result += deg;
    result += CHAR_DEG;
    result += CHAR_SEP;
    result += min;
    result += CHAR_MIN;
    result += CHAR_SEP;
    result += sec.toFixed(2);
    result += CHAR_SEC;
    if (type === CoordinateType.LATITUDE)
        result += value > 0 ? GeoSide.NORTH : GeoSide.SOUTH;
    if (type === CoordinateType.LONGITUDE)
        result += value > 0 ? GeoSide.EAST : GeoSide.WEST;
    return result.toString();

};


export function deg2dec(input: string) {
    const parts = input.split(/[^\d\w]+/);
    return convertDMSToDD(+parts[0], +parts[1], +parts[2], parts[3]).toFixed(6);
}

function convertDMSToDD(degrees: number, minutes: number, seconds: number, direction: string) {
    let dd = degrees + minutes / 60 + seconds / (60 * 60);

    if (direction === 'S' || direction === 'W') {
        dd = dd * -1;
    } // Don't do anything for N or E
    return dd;
}