React = require 'react'
moment = require 'moment'

{div, a} = React.DOM

module.exports =
  
  ###*
    * Return Age from datetstring
    * @param {String} datestring
    * @param {Boolean} return the month default false.
  ###
  formatAge: (datestring, includeMonth) ->
    now  = moment().utc()
    birthDate = moment(datestring).utc()
    
    age = ''
    months = now.diff(birthDate, 'months')

    if months < 1
      days = now.diff(birthDate, 'days')
      age = "#{days} DO"
    else if months < 48
      age = "#{months} MO"
    else
      years = now.diff(birthDate, 'years')
      age = "#{years} YO"

      # Include month in age
      if includeMonth
        months = months-(years*12)
        # don't include if 0 months
        if months then age = "#{years} yrs #{months} mnth"

    return age

  formatNHS: (nhs) ->
    if nhs?
      # Strip non digit characters out of the nhs
      nhs = nhs.replace(/[^0-9]/g, "")
      # If there is not just a 10 digit humber left, return the nhs as is
      if nhs.length != 10 then return nhs
      
      nhs1 = nhs.substr(0,3)
      nhs2 = nhs.substr(3,3)
      nhs3 = nhs.substr(6,4)

      return "#{nhs1}-#{nhs2}-#{nhs3}"
    else
      return ""

  # Returns 10 digit number in (xxx) xxx-xxxx format
  # or 7 digit number in xxx-xxxx format
  formatPhoneNumber: (phone) ->
    if phone? 
      # Make sure the number is a String
      phone = "#{phone}"
      phone = phone.replace(/[^0-9]/g, '')
      if phone.length == 10
        phone = phone.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3")
      if phone.length == 7
        phone = phone.replace(/(\d{3})(\d{4})/, "$1-$2")
      return phone
    else
      return ""

  formatSource: (options) ->
    {orgName, facilityName, systemName} = options

    sourceName = ''

    # Org
    if orgName?
      sourceName += orgName   
    # Facility
    if facilityName? and facilityName not in [orgName, '']
      sourceName += ' - ' if sourceName isnt ''
      sourceName += facilityName
    
    # System
    if (facilityName? or orgName?) and systemName? and systemName isnt ''
      sourceName += ' - ' if sourceName isnt ''
      sourceName += systemName

    sourceName

  formatTimezoneForAPI: (relevantDate) ->
    minutes = moment(relevantDate).utcOffset()
    
    if minutes < 0 then negative = "-"
    else negative = ""
    
    minutes = Math.abs(minutes)
    
    hours = Math.floor(minutes / 60)
    if hours < 10 then hours = "0" + hours
    
    minutestring = minutes % 60
    if minutestring < 10  then minutestring = "0" + minutestring
    
    return "#{negative}#{hours}:#{minutestring}"

  escapeRegExp: (string) ->
    string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")

  isValidEmail : (addr) ->
    # modified RFC 2822 - http://www.regular-expressions.info/email.html
    return /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/.test addr

  # Adding comment to jenkins/github integration.
  # Converts raw bytes to KB, MB, etc
  bytesToSize: (bytes, precision) ->
    unless bytes? then return ''
    kilobyte = 1024
    megabyte = kilobyte * 1024
    gigabyte = megabyte * 1024
    terabyte = gigabyte * 1024
    
    if bytes >= 0 and bytes < kilobyte then return bytes + ' B'
    else if bytes >= kilobyte and bytes < megabyte then return (bytes / kilobyte).toFixed(precision) + ' KB'
    else if bytes >= megabyte and bytes < gigabyte then return (bytes / megabyte).toFixed(precision) + ' MB'
    else if bytes >= gigabyte and bytes < terabyte then return (bytes / gigabyte).toFixed(precision) + ' GB'
    else if bytes >= terabyte then return (bytes / terabyte).toFixed(precision) + ' TB'
    else return bytes + ' B'

  measureScrollBarWidth: ->
    $tester = $("<div id='outer' style='overflow: scroll; height: 500px; width: 500px; position: absolute; top: 100px; left: 100px;'><div id='inner' style='position: absolute; height: 100%; width: 100%;'></div><div style='height: 600px; width: 600px;'></div></div>")
    $('body').append $tester
    scrollBarWidth = $tester.height() - $tester.find('#inner').height()
    $tester.remove()
    return scrollBarWidth

  # Reduces name to targetLength by replacing a middle portion of the name with an ellipses
  formatFileName: (name, targetLength) ->
    
    # Get the starting file name length
    fileLength = name.length
    # Do nothing to files with less than targetLength characters
    if fileLength <= targetLength then return name 
    # Calculate the number of characters that need to be removed to get the filename down to targetLength
    # Add 3 to file length as the file length will technically get larger with the ellipses thus we need to increase the file name length
    # NOTE : it was adding 3 to the targetLength but doing that caused for overlapping characters in the file name    
    removeCount = (fileLength + 3) - targetLength
    # Figure out how far from the end we should keeps characters
    # In most cases this will be 6 characters unless the diff between the target length and the removeCount is 6 or else
    # This will insure the beginning of the file has more than 1 or 2 characters before the ellipses (unless the target length is extremely small like 3)
    if (targetLength - removeCount) <= 6 then charactersFromEnd = 4 else charactersFromEnd = 6
    # Calculate the place the remove should end
    endRemove = fileLength - charactersFromEnd
    # Calculate the postion to start the remove
    startRemove = endRemove - removeCount
    # NOTE: Negative start values cannot be used in substr becuase IE8 does not support them!
    # Get the start of the file
    fileStart = name.substr(0, startRemove)
    # Get the end of the file
    fileEnd = name.substr(endRemove)
    
    return fileStart + "…" + fileEnd

  # Gets file extensions from a file name, returns empty string when there is no extensions
  parseFileExtension: (filename) ->
    filenameSplit = filename.split('.')
    return name = if filenameSplit.length > 1 then filenameSplit[filenameSplit.length - 1] else ''

  # Makes a temparay (somewhat unique) id for use in the GUI before saving a new object to the server
  makeGuid: ->
    'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c) ->
      r = Math.random()*16|0
      v = if c is 'x' then r else (r&0x3|0x8)
      v.toString(16)

  # Checks if two object have the same id or guid
  idsMatch: (itemA, itemB) -> 
    unless itemA? and itemB? then return no
    
    if itemA.id? and itemB.id?
      return itemA.id is itemB.id
    else if itemA.guid? and itemB.guid?
      return itemA.guid is itemB.guid
    else
      return no

  synthesizeMouseEvent: (target, type) ->
    event = document.createEvent('MouseEvents')
    event.initMouseEvent(type, true, true, window)
    target.dispatchEvent(event)

  # Checks to see if input is a number
  isNumber: (input) ->
    return !isNaN(parseFloat(input)) and isFinite(input)

  # Limits a value to only two decimal places
  toFixed: (value) ->
    return Math.round(value * 100) / 100

  # Can measure widths and heights of DOM elements
  measureDOMProp: (el, DOMProp) ->
    measurer = document.getElementById 'measurer'
    measurer.appendChild el
    prop = el[DOMProp]
    measurer.removeChild el
    prop







