'use strict'

pathUtils = require 'path'
fs = require 'fs'
childProcess = require 'child_process'
http = require 'http'
https = require 'https'
utils = require 'src/utils'
log = require 'src/log'
assert = require 'src/assert'

exports.platforms =
    node:
        groups: ['server']
    html:
        groups: ['client', 'browser']
    webgl:
        groups: ['client', 'browser']
    android:
        groups: ['client', 'native']
    ios:
        groups: ['client', 'native', 'apple']
    macos:
        groups: ['client', 'native', 'apple']

exports.getProcessEnvForPlatform = (platform) ->
    config = exports.platforms[platform]
    assert.ok config, "Unknown platform #{platform} given"
    env =
        NEFT_PLATFORM: platform
    for group in config.groups
        env["NEFT_#{group.toUpperCase()}"] = "1"
    env["NEFT_#{platform.toUpperCase()}"] = "1"
    env

exports.verifyNeftProject = (path) ->
    src = pathUtils.resolve path, './package.json'
    unless fs.existsSync(src)
        log.error 'No Neft project found'
        false
    else
        true

exports.forEachFileDeep = (dir, onFile, onEnd) ->
    assert.isString dir
    assert.isFunction onFile
    assert.isFunction onEnd

    ready = length = 0
    onReady = ->
        if ++ready is length
            onEnd null

    proceedFile = (path) ->
        fs.stat path, (err, stat) ->
            if err
                return onEnd err

            if stat.isFile()
                onFile path, stat
                onReady()
            else
                exports.forEachFileDeep path, onFile, onReady

    fs.readdir dir, (err, files) ->
        if err or files.length is 0
            return onEnd err

        for file in files
            if file[0] isnt '.'
                length++
                filePath = "#{dir}/#{file}"
                proceedFile filePath

        return
    return

exports.isPlatformFilePath = do ->
    PLATFORM_TYPES =
        local:
            local: true
        npm:
            npm: true
        node:
            node: true
            server: true
        html:
            html: true
            browser: true
            client: true
        webgl:
            webgl: true
            browser: true
            client: true
        android:
            android: true
            client: true
            native: true
        ios:
            ios: true
            client: true
            native: true
            apple: true
        macos:
            macos: true
            client: true
            native: true
            apple: true

    SPECIAL_EXTS = do ->
        r = {}
        for _, exts of PLATFORM_TYPES
            utils.merge r, exts
        r

    (platform, filePath) ->
        if linkTypeMatch = /^(.+?)\.([a-zA-Z]+)\.([a-zA-Z]+)$/.exec(filePath)
            linkType = linkTypeMatch[2]

            if linkType and SPECIAL_EXTS[linkType]
                return PLATFORM_TYPES[platform][linkType]

        return true

LOCAL_IP = do ->
    cmd = """
        ifconfig | \
        grep -Eo 'inet (addr:)?([0-9]*\\.){3}[0-9]*' | \
        grep -Eo '([0-9]*\\.){3}[0-9]*' | \
        grep -v '127.0.0.1'
    """
    out = try childProcess.execSync cmd, stdio: 'pipe'
    out ?= try childProcess.execSync 'ipconfig getifaddr en0', stdio: 'pipe'
    if out
        String(out).split('\n')[0].trim()
    else
        log.warn "Cannot resolve local IP address; is ifconfig or ipconfig commands available?"
        ''

exports.isLocalHost = (host) ->
    String(host).toLowerCase() is 'localhost'

exports.getValidHost = (host) ->
    if exports.isLocalHost(host) and LOCAL_IP
        LOCAL_IP
    else
        host

READY_TRIES = 10
READY_TRY_DELAY = 500

exports.onUrlAccessible = (protocol, url, callback, tryNo = 0) ->
    switch protocol.toLowerCase()
        when 'http'
            reqModule = http
        when 'https'
            reqModule = https
        else
            callback()
            return
    reqModule.get url, (res) ->
        callback()
    .on 'error', ->
        setTimeout ->
            exports.onUrlAccessible protocol, url, callback, tryNo + 1
        , READY_TRY_DELAY
    return
