import { isNullOrUndefined } from 'util';

/*
 * method to map associative arrays to iterable arrays
 */
export function mapToIterable<T>(associativeArray: any, callback?: (param: T, index?: number) => T): T[] {
  let index = -1;
  return Object.keys(associativeArray).map((t) => {
    if (callback) {
      return callback(associativeArray[t], index++);
    }
    return associativeArray[t];
  });
}

/*
 * function to calculate distance beetwen to points in map
 */
export function distance(lat1: number, lon1: number, lat2: number, lon2: number) {
  if (lat1 === lat2 && lon1 === lon2) {
    return 0;
  } else {
    const radlat1 = (Math.PI * lat1) / 180;
    const radlat2 = (Math.PI * lat2) / 180;
    const theta = lon1 - lon2;
    const radtheta = (Math.PI * theta) / 180;
    let dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    if (dist > 1) {
      dist = 1;
    }
    dist = Math.acos(dist);
    dist = (dist * 180) / Math.PI;
    return dist;
  }
}

/*
 * function to check if array in object has value
 */
export function isArrayOfMinLengthDefined(data: any, properties: string, minLenght: number): boolean {
  if (data) {
    return isArrayMinLength(data, properties, minLenght);
  }

  return false;
}

/*
 * function to check if obejct in has property
 */
export function getProperty(object: any, properties: string) {
  const props = properties.split('.');

  if (object && props.length > 0) {
    props.forEach((prop: string, index: number) => {
      if (!isNullOrUndefined(object[prop]) && index !== props.length - 1) {
        getProperty(object[prop], props.slice(index + 1).join('.'));
      }
    });
  }

  if (object && !isNullOrUndefined(object[properties])) {
    return object[properties];
  }

  return null;
}

/*
 * function to check if value is an array
 */
export function isArray(data: any) {
  return Array.isArray(data);
}

/*
 * function to check if array lenght has at least so many items as passed down with the minLenght
 */
export function isArrayMinLength(object: any, property: string, minLenght: number) {
  if (property) {
    const data = getProperty(object, property);
    if (data && isArray(data)) {
      return data.length > minLenght;
    }
  } else {
    if (isArray(object)) {
      return object.length > minLenght;
    }
  }

  return false;
}

/*
 * function to which convert our date format to iso for api
 */
export function isoDateFromString(date: string): string {
  if (date) {
    const [day, month, year] = date.split('.');
    const isoDate = new Date(+year, +month - 1, +day).toISOString();
    return isoDate;
  }

  return '';
}

/*
 * function which checks if property is boolean
 */
export function isBoolean(object: any, property: string) {
  if (property) {
    const data = getProperty(object, property);
    if (data) {
      return typeof data === 'boolean';
    }
  } else {
    if (object) {
      return typeof object === 'boolean';
    }
  }

  return false;
}

/*
 * function which checks if object has any values
 */
export function objectNotNull(object: any) {
  return object && Object.keys(object).length > 0;
}

/*
 * function which check if object is undefined and return null if so
 */
export function safeNull(object: any) {
  return object ? object : null;
}

export function areArraysEqual(value, other) {
  try {
    // Get the value type
    const type = Object.prototype.toString.call(value);

    // If the two objects are not the same type, return false
    if (type !== Object.prototype.toString.call(other)) {
      return false;
    }

    // If items are not an object or array, return false
    if (['[object Array]', '[object Object]'].indexOf(type) < 0) {
      return false;
    }

    // Compare the length of the length of the two items
    const valueLen = type === '[object Array]' ? value.length : Object.keys(value).length;
    const otherLen = type === '[object Array]' ? other.length : Object.keys(other).length;
    if (valueLen !== otherLen) {
      return false;
    }

    // Compare two items
    const compare = function (item1, item2) {
      // Get the object type
      const itemType = Object.prototype.toString.call(item1);

      // If an object or array, compare recursively
      if (['[object Array]', '[object Object]'].indexOf(itemType) >= 0) {
        if (!this.isEqual(item1, item2)) {
          return false;
        } // Otherwise, do a simple comparison
      } else {
        // If the two items are not the same type, return false
        if (itemType !== Object.prototype.toString.call(item2)) {
          return false;
        }

        // Else if it's a function, convert to a string and compare
        // Otherwise, just compare
        if (itemType === '[object Function]') {
          if (item1.toString() !== item2.toString()) {
            return false;
          }
        } else {
          if (item1 !== item2) {
            return false;
          }
        }
      }
    };

    // Compare properties
    if (type === '[object Array]') {
      for (let i = 0; i < valueLen; i++) {
        if (compare(value[i], other[i]) === false) {
          return false;
        }
      }
    } else {
      for (const key in value) {
        if (value.hasOwnProperty(key)) {
          if (compare(value[key], other[key]) === false) {
            return false;
          }
        }
      }
    }

    // If nothing failed, return true
    return true;
  } catch (error) {
    return false;
  }
}

export function undefinedToEmptyStringOrValue(val: string) {
  if (val) {
    return val;
  }
  return '';
}

export function isEmptyString(val: string) {
  if (val === null || val === undefined || val === '') {
    return true;
  }
  return false;
}

export function is(val1: any, val2: any) {
  return val1 === val2;
}

export function scrollToFirstInvalidElement() {
  setTimeout(() => {
    const invalidElements = document.getElementsByClassName('invalid-feedback');
    if (invalidElements) {
      const firstInvalidElement = invalidElements.item(0);
      if (firstInvalidElement) {
        firstInvalidElement.scrollIntoView({ block: 'center' });
      }
    }
  }, 500);
}
