#!/usr/bin/env python
import getopt, sys
import glob
import urllib2_file
import urllib2
import httplib
import shutil
import re
import webbrowser
from threading import Timer
import tarfile

from m5.compiler import *
from m5.server import *
from m5.app import M5App

self_dir = os.path.dirname(__file__)
if re.search('scripts$', self_dir):
    M5_DIR = os.path.join(self_dir, "../../")
else:
    M5_DIR = os.path.join(self_dir, "..")
print "M5 install dir: " + M5_DIR

class PutRequest(urllib2.Request):
    def get_method(self):
        return "PUT"

def print_help():
    print "Usage: m5 <command> <options>\n"
    print "m5 create [--template=name] <path> - Create new app at path"
    print "m5 server [-e <environment> --examples --simulator --nb -p <port>] - Run the local web server for the current app"
    print "m5 compile - Expands dynamic entries in your app.html file to generate index.html"
    print "m5 deploy [--scratchpad] - Deploy the current app"
    print "m5 tutorial - Start the tutorial server"
    
  
def create_app(path,template=None):
    # Copy app template
    if os.path.exists(path):
        print "Error: path " + path + " already exists"
        exit()
    else:
        template = template or "cities"
        print "Creating new app " + path + " from template '" + template + "'..."
        app_name = os.path.basename(path)
        shutil.copytree(os.path.join(M5_DIR, "templates", template), path)
        print "  -> " + path
        for f in glob.glob(os.path.join(M5_DIR, "templates", "*.js")):
            tf = open(os.path.join(path, os.path.basename(f)), "w")
            tf.write(re.sub("%%NAME%%", app_name, open(f).read()))
            tf.close()
            # shutil.copyfile(f, os.path.join(path, os.path.basename(f)))
            # if re.search("m5\.env\.development\.js", f):
            #     envf = open(os.path.join(path, os.path.basename(f)), 'a')
            #     envf.write("M5.settings.app_name = '" + app_name + "'\n");
            #     envf.close()
            print "  -> " + os.path.basename(f)
        manifest = open(os.path.join(M5_DIR, "templates", "manifest.json")).read()
        manifest = re.sub("%%NAME%%", app_name, manifest)
        f = open(os.path.join(path, "manifest.json"), "w")
        f.write(manifest)
        f.close
        print "  -> manifest.json"
        shutil.copy(os.path.join(M5_DIR, "templates", ".gitignore"), path)
        print "  -> .gitignore"
        print "done"

def run_server(example = False, launchsim = False, environment="development",open_browser=False, port=8000):
    print "Running M5 web server with " + environment + " environment ..."
    callback = None
    if open_browser:
        callback = open_simulator
    
    start_m5server(M5_DIR, environment=environment, include_sim=launchsim, port=port, callback=callback)

def open_simulator(port = 8000):
    try:
        webbrowser.open("http://localhost:%d" % port)
    except:
        pass
        
def open_tutorial_browser():
    webbrowser.open("http://localhost:7777")
        
def run_tutorial_server(open_browser=True):
    print "Serving M5 tutorial pages..."
    if open_browser:
        Timer(2.5, open_tutorial_browser).start()
    start_tutorial(os.path.join(M5_DIR, "docs", "tutorial"))
    
def deploy_app(remote_addr):
    print "Deploying app..."
    
    remote_addr = remote_addr or "http://m5apps.org"
    
    app = M5App("foo", ".")
    if not os.path.exists("build"):
        build_app()
    os.chdir("build")
    fileList = []
    rootdir = "."
    for root, subFolders, files in os.walk(rootdir):
        for file in files:
            fileList.append(os.path.join(root,file))

    fname = "../" + app.name + ".build.tar"
    tarf = tarfile.open(fname, "w")
    for f in fileList:
        tarf.add(f)
    tarf.close()

    # httplib approach
    addr = re.sub("http://", "", remote_addr)
    print addr
    connection =  httplib.HTTPConnection(addr)
    body_content = open(fname, "rb").read()
    connection.request('PUT', "/app/" + app.name + "/upload", body_content)
    print connection.getresponse().read()
    os.remove(fname)
    
def build_app():
    if os.path.exists("build"):
        shutil.rmtree("build")
    shutil.copytree(".", "./build", ignore=shutil.ignore_patterns("*.pyc", "build/*","app.m5.html","\.DS_Store"))    
    name = "build/app.html"
    print "Building " + name + "... into build"
    if not os.path.exists(os.path.join("build", "lib")):
        os.mkdir(os.path.join("build", "lib"))
    #shutil.copytree(os.path.join(M5_DIR, "jqtouch"), os.path.join("build", "lib", "jqtouch"))
    shutil.copytree(os.path.join(M5_DIR, "jquery-mobile"), os.path.join("build", "lib", "jquery-mobile"))
    shutil.copytree(os.path.join(M5_DIR, "lib"), os.path.join("build", "lib", "m5"))
    for f in glob.glob(os.path.join(M5_DIR, "lib", "*.*")):
        shutil.copy(f, os.path.join("build", "lib"))
    
    app_file = "app.m5.html"
    app = M5App(os.path.basename(app_file), os.path.dirname(app_file))
    if app.inline_js("production"):
        print "Inlining javascript"
    if app.inline_css("production"):
        print "Inlining styles"
    f = open(name, 'w')
    f.write(M5Compiler().compile(app_file, environment="production", include_sim=False, src_dir="build", m5_app = app))
    f.close()
    print "done."
        
def main():
    if len(sys.argv) < 2:
        print_help()
        sys.exit(2)

    command = sys.argv[1]
    try:
        opts, args = getopt.getopt(sys.argv[2:], "he:sp:", ["help", "examples","simulator","nb","remote=","template="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        print_help()
        sys.exit(2)
    examples = False
    launchsim = False
    environment = "development"
    open_browser = True
    remote_addr = None
    template = None
    port = 8000
    for o, arg in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o == "--examples":
            examples = True
        elif o == "-p":
            port = int(arg)
        elif o in ("--simulator"):
            launchsim = True
        elif o == "--nb":
            open_browser = False
        elif o == "--template":
            template = arg
        elif o in ("-e"):
            environment = arg
            if not environment in ("development","production","testing"):
                print "Error, unknown environment: " + arg
                environment = "development"
        elif o == "--remote":
            remote_addr = arg
        else:
            assert False, "unknown option: " + o

    if command == "help":
        print_help();
        sys.exit(0)
    elif command == "tutorial":
        run_tutorial_server(open_browser=open_browser);
    elif command == "server":
        run_server(example = examples, launchsim = launchsim, environment = environment, open_browser=open_browser, port = port)
    elif command == "create":
        create_app(args[0], template=template)
    elif command == "deploy":
        deploy_app(remote_addr)
    elif command == "build":
        build_app()
    else:
        print "Error, unknown command: " + command
        sys.exit(2)

if __name__ == "__main__":
    main()
