#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Dehydra and Treehydra scriptable static analysis tools
# Copyright (C) 2007-2010 The Mozilla Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Author: Taras Glek
# OSX support by Vlad Sukhoy
import getopt, sys, os.path, os, platform, subprocess, tempfile

def usage():
    print """
Usage: ./configure ...
--js-name= part between lib and .so in libjs.so on your system (Usually js, mozjs on Ubuntu)
--js-libs= Location of libjs.so
--js-headers= SpiderMonkey headers, location of jsapi.h. Might get autodetected correctly from --js-libs.
--enable-C Enable experimental C support""".lstrip()
    pass

def error(msg):
    print >> sys.stderr, "Error: " + msg
    sys.exit(1)

def checkdir(path,opt):
    print "Checking " + opt + ": " + path
    if not os.path.isdir (path):
        error("directory '"+path+"' doesn't exist, specify correct directory with --" + opt)

def getjsdirs(jsname, jslibs, jsheaders):
    if jslibs == None:
        libjs = "/usr/lib/lib" + jsname + dynamic_lib_suffix
        if (os.path.isfile (libjs)):
            jslibs = os.path.dirname(libjs)
            print "Detected JavaScript library: " + libjs
    else:
        jslibs = os.path.realpath(jslibs)
        checkdir (jslibs, "js-libs")

    if jsheaders != None:
        checkdir (jsheaders, "js-headers")
    elif jslibs != None:
        jsapi = os.path.dirname(os.path.normpath(jslibs)) + "/include/" + jsname + "/jsapi.h"
        if (os.path.isfile (jsapi)):
            jsheaders = os.path.dirname(jsapi)
            print "Detected JavaScript headers: " + jsheaders

    return (jslibs, jsheaders)

def detect_cxx(config):
    sys.stdout.write ("Checking for a C++ compiler: ")
    cxx="g++"
    try:
        cxx = os.environ["CXX"]
    except:
        pass
    config["CXX"] = cxx
    sys.stdout.write ("%s\n" % cxx)

def try_enable_finish_decl(config):
    print("Checking for FINISH_DECL callback:")
    cxx = config["CXX"]
    file = tempfile.NamedTemporaryFile("w+b", -1, ".c")
    file.write(
"""#include "gcc-plugin.h"
enum plugin_event p = PLUGIN_FINISH_DECL;
""")
    file.flush()
    po = subprocess.Popen(cxx + " -c -o /dev/null " + 
        config["GCC_PLUGIN_HEADERS"] + " " + file.name, shell=True,
        close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if po.wait() == 0:
        config['FINISH_DECL'] = "yes"
        print("FINISH_DECL callback enabled");
    else:
        print("FINISH_DECL callback disabled");
    file.close()

def try_gcc_plugin_headers(config):
    cxx = config["CXX"]
    sys.stdout.write ("Checking for %s plugin headers: " % cxx)
    proc = subprocess.Popen(cxx + ' -print-file-name=', shell=True,
        stdout=subprocess.PIPE, close_fds=True)
    path = os.path.join(proc.stdout.read().strip(), 'plugin', 'include')

    if not os.path.exists(path):
        raise Exception(cxx + " doesn't have plugin headers!")

    path = os.path.abspath(path)
    config["GCC_PLUGIN_HEADERS"] = "-I%s" % (path)
    print(path)
    try_enable_finish_decl(config)



if __name__ == "__main__":
    dynamic_lib_suffix, shared_link_flags = ('.so', '-shared') 
    cflags = ''
    if platform.system() == 'Darwin' :
        dynamic_lib_suffix, shared_link_flags = ('.dylib',
            '-bundle -flat_namespace -undefined suppress')
        cflags += '-fnested-functions'

    try:
        opts, args = getopt.getopt(sys.argv[1:], "h",
                                   ["js-name=", "js-libs=", "js-headers=", "enable-C"])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        usage()
        sys.exit(2)
    jsname = "mozjs"
    jsnamels = [jsname, "js"]
    jslibs = None
    jsheaders = None
    Csupport = False
    for o, val in opts:
        if o == "--js-name":
            jsname = val
            jsnamels = [jsname]
        elif o == "--js-libs":
            jslibs = os.path.expanduser(val)
        elif o == "--js-headers":
            jsheaders = os.path.expanduser(val)
        elif o == "--enable-C":
            Csupport = True
        elif o in ("-h", "--help"):
            usage()
            exit(0)
        else:
            error("unhandled option " +  o)
    #Detect js stuff
    for loop_jsname in jsnamels:
        before = [jslibs, jsheaders]
        jslibs, jsheaders = getjsdirs(loop_jsname, jslibs, jsheaders)
        jsname = loop_jsname
        if (jslibs != None and jsheaders != None) or [jslibs, jsheaders] != before:
            break
    if jslibs == None:
        error("Must indicate javascript library directory with --js-libs=")
    if jsheaders == None:
        error("Must indicate javascript header directory with --js-headers=")
    
    if os.environ.has_key("CFLAGS"):
        cflags += ' ' + os.environ["CFLAGS"]
    config =dict(SM_NAME=jsname, SM_SUFFIX=dynamic_lib_suffix,
              SM_INCLUDE=jsheaders, SM_LIBDIR=jslibs,
              SHARED_LINK_FLAGS=shared_link_flags, 
              CONFIGURE_CFLAGS=cflags)
    if Csupport:
        config['C_SUPPORT'] = "yes"
        print("Experimental C testsuite is enabled");
    else:
        print("Disabling C testsuite");
    detect_cxx(config)
    try_gcc_plugin_headers(config)
    f = open("config.mk", "w")
    f.write("""# %s
%s
""" % (" ".join(["'" + a + "'" for a in sys.argv]),
       "\n".join([k + "=" + str(v) for k, v in config.iteritems()])))
    f.close()
    f = open("dehydra-config.h", "w")
    f.write("""#ifndef DEHYDRA_CONFIG_H
#define DEHYDRA_CONFIG_H
%s
#endif
""" % ("\n".join(["#define CFG_%s \"%s\"" % (k,str(v).replace('"','\\"')) 
                  for k, v in config.iteritems()])))
    f.close()

    if os.path.exists("Makefile"):
        os.unlink("Makefile")
    os.symlink ("Makefile.in", "Makefile")
    
