#!/bin/bash -e
set -e
has() {
  type "$1" > /dev/null 2>&1
}

# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"
# exec > >(tee /tmp/installlog.txt)

# Without this, only stdout would be captured - i.e. your
# log file would not contain any error messages.
exec 2>&1

if has "wget"; then
  DOWNLOAD() {
    wget --no-check-certificate -nc -O "$2" "$1"
  }
elif has "curl"; then
  DOWNLOAD() {
    curl -sSL -o "$2" "$1"
  }
else
  echo "Error: you need curl or wget to proceed" >&2;
  exit 1
fi

C9_DIR=$HOME/.c9
if [[ ${1-} == -d ]]; then
    C9_DIR=$2
    shift 2
fi

# Check if C9_DIR exists
if [ ! -d "$C9_DIR" ]; then
  mkdir -p $C9_DIR
fi

VERSION=1
NODE_VERSION=v6.3.1
NODE_VERSION_ARM_PI=v0.10.28
NPM=$C9_DIR/node/bin/npm
NODE=$C9_DIR/node/bin/node

export TMP=$C9_DIR/tmp
export TMPDIR=$TMP

PYTHON=python

# node-gyp uses sytem node or fails with command not found if
# we don't bump this node up in the path
PATH="$C9_DIR/node/bin/:$C9_DIR/node_modules/.bin:$PATH"

start() {
  if [ $# -lt 1 ]; then
    start base
    return
  fi

  check_deps
  
  # Try to figure out the os and arch for binary fetching
  local uname="$(uname -s)"
  local os=
  local arch="$(uname -m)"
  case "$uname" in
    Linux*) os=linux ;;
    Darwin*) os=darwin ;;
    SunOS*) os=sunos ;;
    FreeBSD*) os=freebsd ;;
    CYGWIN*) os=windows ;;
    MINGW*) os=windows ;;
  esac
  case "$arch" in
    *arm64*) arch=arm64 ;;
    *aarch64*) arch=arm64 ;;
    *armv6l*) arch=armv6l ;;
    *armv7l*) arch=armv7l ;;
    *x86_64*) arch=x64 ;;
    *i*86*) arch=x86 ;;
    *)
      echo "Unsupported Architecture: $os $arch" 1>&2
      exit 1
    ;;
  esac

  if [ "$arch" == "x64" ] && [[ $HOSTTYPE == i*86 ]]; then
    arch=x86 # check if 32 bit bash is installed on 64 bit kernel
  fi

  if [ "$os" != "linux" ] && [ "$os" != "darwin" ]; then
    echo "Unsupported Platform: $os $arch" 1>&2
    exit 1
  fi

  case $1 in
    "help" )
      echo
      echo "Cloud9 Installer"
      echo
      echo "Usage:"
      echo "    install help                       Show this message"
      echo "    install install [name [name ...]]  Download and install a set of packages"
      echo "    install ls                         List available packages"
      echo
    ;;

    "ls" )
      echo "!node - Node.js"
      echo "!tmux - TMUX"
      echo "!nak - NAK"
      echo "!ptyjs - pty.js"
      echo "!collab - collab"
      echo "coffee - Coffee Script"
      echo "less - Less"
      echo "sass - Sass"
      echo "typescript - TypeScript"
      echo "stylus - Stylus"
      # echo "go - Go"
      # echo "heroku - Heroku"
      # echo "rhc - RedHat OpenShift"
      # echo "gae - Google AppEngine"
    ;;
    
    "install" )
      shift
    
      # make sure dirs are around
      mkdir -p "$C9_DIR"/bin
      mkdir -p "$C9_DIR"/tmp
      mkdir -p "$C9_DIR"/node_modules
    
      # install packages
      while [ $# -ne 0 ]
      do
        if [ "$1" == "tmux" ]; then
          cd "$C9_DIR"
          time tmux_install $os $arch
          shift
          continue
        fi
        cd "$C9_DIR"
        time eval ${1} $os $arch
        shift
      done
      
      # finalize
      pushd "$C9_DIR"/node_modules/.bin
      for FILE in "$C9_DIR"/node_modules/.bin/*; do
        FILE=$(readlink "$FILE")
        # can't use the -i flag since it is not compatible between bsd and gnu versions
        sed -e's/#!\/usr\/bin\/env node/#!'"${NODE//\//\\/}/" "$FILE" > "$FILE.tmp-sed"
        mv "$FILE.tmp-sed" "$FILE"
      done
      popd
      
      echo $VERSION > "$C9_DIR"/installed
      
      cd "$C9_DIR"
      DOWNLOAD https://raw.githubusercontent.com/c9/install/master/packages/license-notice.md "Third-Party Licensing Notices.md"
      
      echo :Done.
    ;;
    
    "base" )
      echo "Installing base packages. Use --help for more options"
      start install node tmux_install nak ptyjs collab
    ;;
    
    * )
      start base
    ;;
  esac
}

check_deps() {
  local ERR
  local OS
  
  if [[ `cat /etc/os-release 2>/dev/null` =~ CentOS ]]; then
    OS="CentOS"
  elif [[ `cat /proc/version 2>/dev/null` =~ Ubuntu|Debian ]]; then
    OS="DEBIAN"
  fi

  for DEP in make gcc; do
    if ! has $DEP; then
      echo "Error: please install $DEP to proceed" >&2
      if [ "$OS" == "CentOS" ]; then
        echo "To do so, log into your machine and type 'yum groupinstall -y development'" >&2
      elif [ "$OS" == "DEBIAN" ]; then
        echo "To do so, log into your machine and type 'sudo apt-get install build-essential'" >&2
      fi
      ERR=1
    fi
  done
  
  # CentOS
  if [ "$OS" == "CentOS" ]; then
    if ! yum list installed glibc-static >/dev/null 2>&1; then
      echo "Error: please install glibc-static to proceed" >&2
      echo "To do so, log into your machine and type 'yum install glibc-static'" >&2
      ERR=1
    fi
  fi
  
  check_python
  
  if [ "$ERR" ]; then exit 1; fi
}

check_python() {
  if type -P python2.7 &> /dev/null; then
    PYTHONVERSION="2.7"
    PYTHON="python2.7"
  elif type -P python &> /dev/null; then
    PYTHONVERSION=`python -c 'import sys; print(".".join(map(str, sys.version_info[:2])))'`
    PYTHON="python"
  fi

  if [[ $PYTHONVERSION != "2.7" ]]; then
    echo "Python version 2.7 is required to install pty.js. Please install python 2.7 and try again. You can find more information on how to install Python in the docs: https://docs.aws.amazon.com/cloud9/latest/user-guide/ssh-settings.html#ssh-settings-requirements"
    exit 100
  fi
}

# NodeJS

download_virtualenv() {
  VIRTUALENV_VERSION="virtualenv-12.0.7"
  DOWNLOAD "https://pypi.python.org/packages/source/v/virtualenv/$VIRTUALENV_VERSION.tar.gz" $VIRTUALENV_VERSION.tar.gz
  tar xzf $VIRTUALENV_VERSION.tar.gz
  rm $VIRTUALENV_VERSION.tar.gz
  mv $VIRTUALENV_VERSION virtualenv
}

ensure_local_gyp() {
  # when gyp is installed globally npm install pty.js won't work
  # to test this use `sudo apt-get install gyp`
  if [ `"$PYTHON" -c 'import gyp; print gyp.__file__' 2> /dev/null` ]; then
    echo "You have a global gyp installed. Setting up VirtualEnv without global pakages"
    rm -rf virtualenv
    rm -rf python
    if has virtualenv; then
      virtualenv -p python2 "$C9_DIR/python"
    else
      download_virtualenv
      "$PYTHON" virtualenv/virtualenv.py "$C9_DIR/python"
    fi
    if [[ -f "$C9_DIR/python/bin/python2" ]]; then
      PYTHON="$C9_DIR/python/bin/python2"
    else
      echo "Unable to setup virtualenv"
      exit 1
    fi
  fi
  "$NPM" config -g set python "$PYTHON"
  "$NPM" config -g set unsafe-perm true
  
  local GYP_PATH=$C9_DIR/node/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js
  if [ -f  "$GYP_PATH" ]; then
    ln -s "$GYP_PATH" "$C9_DIR"/node/bin/node-gyp &> /dev/null || :
  fi
}

node(){
  # clean up 
  rm -rf node 
  rm -rf node.tar.gz
  
  echo :Installing Node $NODE_VERSION
  
  DOWNLOAD https://nodejs.org/dist/"$NODE_VERSION/node-$NODE_VERSION-$1-$2.tar.gz" node.tar.gz
  tar xzf node.tar.gz
  mv "node-$NODE_VERSION-$1-$2" node
  rm -f node.tar.gz

  # use local npm cache
  "$NPM" config -g set cache  "$C9_DIR/tmp/.npm"
  ensure_local_gyp

}

compile_tmux(){
  cd "$C9_DIR"
  echo ":Compiling libevent..."
  tar xzf libevent-2.1.8-stable.tar.gz
  rm libevent-2.1.8-stable.tar.gz
  cd libevent-2.1.8-stable
  echo ":Configuring Libevent"
  ./configure --disable-shared --prefix="$C9_DIR/local"
  echo ":Compiling Libevent"
  make
  echo ":Installing libevent"
  make install
 
  cd "$C9_DIR"
  echo ":Compiling ncurses..."
  tar xzf ncurses-6.0.tar.gz
  rm ncurses-6.0.tar.gz
  cd ncurses-6.0
  echo ":Configuring Ncurses"
  CPPFLAGS=-P ./configure --prefix="$C9_DIR/local" --without-tests --without-cxx
  echo ":Compiling Ncurses"
  make
  echo ":Installing Ncurses"
  make install
 
  cd "$C9_DIR"
  echo ":Compiling tmux..."
  tar xzf tmux-2.2.tar.gz
  rm tmux-2.2.tar.gz
  cd tmux-2.2
  echo ":Configuring Tmux"
  ./configure CFLAGS="-I$C9_DIR/local/include -I$C9_DIR/local/include/ncurses" LDFLAGS="-static-libgcc -L$C9_DIR/local/lib" --prefix="$C9_DIR/local"
  echo ":Compiling Tmux"
  make
  echo ":Installing Tmux"
  make install
}

tmux_download(){
  echo ":Downloading tmux source code"
  echo ":N.B: This will take a while. To speed this up install tmux 2.2 manually on your machine and restart this process."
  
  echo ":Downloading Libevent..."
  DOWNLOAD https://raw.githubusercontent.com/c9/install/master/packages/tmux/libevent-2.1.8-stable.tar.gz libevent-2.1.8-stable.tar.gz
  echo ":Downloading Ncurses..."
  DOWNLOAD https://github.com/c9/install/raw/master/packages/tmux/ncurses-6.0.tar.gz ncurses-6.0.tar.gz
  echo ":Downloading Tmux..."
  # DOWNLOAD https://raw.githubusercontent.com/c9/install/master/packages/tmux/tmux-1.9.tar.gz
  DOWNLOAD https://github.com/tmux/tmux/releases/download/2.2/tmux-2.2.tar.gz tmux-2.2.tar.gz
}

check_tmux_version(){
  if [ ! -x "$1" ]; then
    return 1
  fi
  tmux_version=$($1 -V | sed -e's/^[a-z0-9.-]* //g' | sed -e's/[a-z]*$//')  
  if [ ! "$tmux_version" ]; then
    return 1
  fi

  if [ "$("$PYTHON" -c "print 1.7<=$tmux_version and $tmux_version <= 2.2")" == "True" ]; then
    return 0
  else
    return 1
  fi
}

tmux_install(){
  echo :Installing TMUX
  mkdir -p "$C9_DIR/bin"
  if check_tmux_version "$C9_DIR/bin/tmux"; then
    echo ':Existing tmux version is up-to-date'
  
  # If we can support tmux 1.9 or detect upgrades, the following would work:
  elif has "tmux" && check_tmux_version "$(which tmux)"; then
    echo ':A good version of tmux was found, creating a symlink'
    ln -sf "$(which tmux)" "$C9_DIR"/bin/tmux
    return 0
  
  # If tmux is not present or at the wrong version, we will install it
  else
    if [ $os = "darwin" ]; then
      if ! has "brew"; then
        # http://brew.sh/
        DOWNLOAD https://raw.githubusercontent.com/Homebrew/install/master/install installbrew
        ruby installbrew
      fi
      brew install tmux > /dev/null ||
        (brew remove tmux &>/dev/null && brew install tmux >/dev/null)
      ln -sf "$(which tmux)" "$C9_DIR"/bin/tmux
    # Linux
    else
      if ! has "make"; then
        echo ":Could not find make. Please install make and try again."
        exit 100;
      fi
    
      tmux_download  
      compile_tmux
      ln -sf "$C9_DIR"/local/bin/tmux "$C9_DIR"/bin/tmux
    fi
  fi
  
  if ! check_tmux_version "$C9_DIR"/bin/tmux; then
    echo "Installed tmux does not appear to work:"
    exit 100
  fi
}

collab(){
  echo :Installing Collab Dependencies
  "$NPM" cache clean
  "$NPM" install sqlite3@3.1.4
  "$NPM" install sequelize@2.0.0-beta.0
  mkdir -p "$C9_DIR"/lib
  cd "$C9_DIR"/lib
  DOWNLOAD https://raw.githubusercontent.com/c9/install/master/packages/sqlite3/linux/sqlite3.tar.gz sqlite3.tar.gz
  tar xzf sqlite3.tar.gz
  rm sqlite3.tar.gz
  ln -sf "$C9_DIR"/lib/sqlite3/sqlite3 "$C9_DIR"/bin/sqlite3
}

nak(){
  echo :Installing Nak
  "$NPM" install https://github.com/c9/nak/tarball/c9
}

ptyjs(){
  echo :Installing pty.js
  "$NPM" install node-pty-prebuilt@0.7.3

  if ! hasPty; then
    echo "Unknown exception installing pty.js"
    "$C9_DIR/node/bin/node" -e "console.log(require('node-pty-prebuilt'))"
    exit 100
  fi
}

hasPty() {
  local HASPTY=$("$C9_DIR/node/bin/node" -p "typeof require('node-pty-prebuilt').createTerminal=='function'" 2> /dev/null)
  if [ "$HASPTY" != true ]; then
    return 1
  fi
}

coffee(){
  echo :Installing Coffee Script
  "$NPM" install coffee
}

less(){
  echo :Installing Less
  "$NPM" install less
}

sass(){
  echo :Installing Sass
  "$NPM" install sass
}

typescript(){
  echo :Installing TypeScript
  "$NPM" install typescript  
}

stylus(){
  echo :Installing Stylus
  "$NPM" install stylus  
}

# go(){
  
# }

# heroku(){
  
# }

# rhc(){
  
# }

# gae(){
  
# }

start "$@"

# cleanup tmp files
rm -rf "$C9_DIR/tmp"
