#!/usr/bin/python
# coding=utf-8

import os
import sys
import argparse
import logging
from distutils.spawn import find_executable
from itertools import ifilterfalse
import tarfile

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

def download(url, local_path=None):
    import urllib2
    resp = urllib2.urlopen(url)

    content_disp = resp.info().get('Content-Disposition')

    if local_path:
        local_path = local_path
    elif content_disp:
        local_path = content_disp.split('filename=')[1].strip('\'\" ')
    else:
        local_path = os.path.basename(url)

    if os.path.exists(local_path):
        logger.warning('%s exists, not saved', local_path)
    else:
        with open(local_path, 'wb') as f:
            f.write(resp.read())
            logger.info('Saved as %s', local_path)

    return local_path

def has_executable(prog):
    '''
    >>> has_executable('ls')
    True
    >>> has_executable('lllsss')
    False
    '''
    return True if find_executable(prog) else False

def run(cmd, echo=True):
    import subprocess
    logger.info(cmd)
    return subprocess.call(cmd, shell=True)

def fatal_exit(msg, status=1):
    logger.fatal(msg)
    sys.exit(status)

if __name__ == '__main__':
    # check dependencies
    deps = ['gcc', 'curl', 'make',]
    not_satisfied = list(ifilterfalse(has_executable, deps))
    if len(not_satisfied):
        fatal_exit('%s not found!' % ' '.join(not_satisfied))

    # get active virtualenv
    active_env = os.environ.get('VIRTUAL_ENV')
    if not active_env:
        fatal_exit('Must be in virtualenv')

    parser = argparse.ArgumentParser(description='Install Nodejs in active python virtualenv')
    parser.add_argument('-v', '--version', default='0.10.33',
                        help="Nodejs version to install")
    parser.add_argument('--doctest', action='store_true',
                        help="run doctest")

    args = parser.parse_args()

    if args.doctest:
        import doctest
        doctest.testmod()

    logger.info('node version: %s' % args.version)

    nodejs_url = "http://nodejs.org/dist/v%(version)s/node-v%(version)s.tar.gz" \
        % {'version': args.version}

    # Create and enter tmp path
    tmp_path = os.path.join(active_env, 'tmp')
    logger.info('mkdir %s' % tmp_path)
    os.path.isdir(tmp_path) or os.makedirs(tmp_path)
    os.chdir(tmp_path)

    # Download nodejs
    nodejs_ball = os.path.join(tmp_path, os.path.basename(nodejs_url))
    if os.path.exists(nodejs_ball):
        logger.info('%s alreay exists, not download' % nodejs_ball)
    else:
        logger.info('start download nodejs: %s to %s' % (nodejs_url, nodejs_ball))
        download(nodejs_url, nodejs_ball)

    # Extract
    logger.info('Extracting %s' % nodejs_ball)
    with tarfile.open(nodejs_ball) as tf:
        tf.extractall()

    nodejs_src_dir = nodejs_ball.replace('.tar.gz', '')
    logger.info('Get into %s' % nodejs_src_dir)
    os.chdir(nodejs_src_dir)

    if run('./configure --prefix=%s' % active_env) != 0:
        fatal_exit('configure failed')

    if run('make -j4') != 0:
        fatal_exit('compile failed')

    if run('make install') != 0:
        fatal_exit('install failed')

    logger.info('Install npm')
    if run('curl -L https://www.npmjs.com/install.sh | sh') != 0:
        fatal_exit('install failed')
