<commit_before>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "TiRootObject.h"

#include "NativeStringInterface.h"
#include "TiGenericFunctionObject.h"
#include "TiLocaleObject.h"
#include "TiLogger.h"
#include "TiMessageStrings.h"
#include "TiTitaniumObject.h"
#include "TiTimeoutManager.h"
#include "TiV8EventContainerFactory.h"
#include "V8Utils.h"
#include <QSettings>

#include <fstream>
#include <sstream>

#include <QString>
#include <QUrl>

#include <unistd.h>

using namespace titanium;

static Handle<ObjectTemplate> g_rootTemplate;
static const string rootFolder = "app/native/assets/";

// Application properties defined at compile in tiapp.xml
// can be read using this settings instance. It is read only.
static QSettings defaultSettings("app/native/assets/app_properties.ini",
                                 QSettings::IniFormat);

TiRootObject::TiRootObject()
    : TiObject("")
{
}

TiRootObject::~TiRootObject()
{
    if (!context_.IsEmpty())
    {
        context_.Dispose();
    }
    NativeStringInterface::deleteInstance();
}

void TiRootObject::onCreateStaticMembers()
{
    TiObject* ti = TiTitaniumObject::createObject(objectFactory_);
    addMember(ti);
    addMember(ti, "Ti");

    createStringMethods();
    TiGenericFunctionObject::addGenericFunctionToParent(this, "L", this, _L);   // TODO: use the same object as Ti.Locale.getString
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearInterval", this, _clearInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearTimeout", this, _clearTimeout);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "globalRequire", this, _globalRequire);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setInterval", this, _setInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setTimeout", this, _setTimeout);
}

VALUE_MODIFY TiRootObject::onChildValueChange(TiObject* childObject, Handle<Value>, Handle<Value> newValue)
{
    Local<Object> obj = getValue()->ToObject();
    obj->Set(String::New(childObject->getName()), newValue);
    return VALUE_MODIFY_ALLOW;
}

void TiRootObject::addMember(TiObject* object, const char* name)
{
    TiObject::addMember(object, name);
    if (name == NULL)
    {
        name = object->getName();
    }
    Handle<Object> obj = getValue()->ToObject();
    Handle<Value> newValue = object->getValue();
    if (newValue.IsEmpty())
    {
        newValue = globalTemplate_->NewInstance();
        object->forceSetValue(newValue);
        TiObject::setTiObjectToJsObject(newValue, object);
    }
    obj->Set(String::New(name), newValue);
}

TiRootObject* TiRootObject::createRootObject()
{
    TiRootObject* obj = new TiRootObject;
    return obj;
}

int TiRootObject::executeScript(NativeObjectFactory* objectFactory, const char* javaScript,
                                MESSAGELOOPENTRY messageLoopEntry, void* context)
{
    HandleScope handleScope;
    objectFactory_ = objectFactory;
    globalTemplate_ = ObjectTemplate::New();
    TiV8EventContainerFactory* eventFactory = TiV8EventContainerFactory::createEventContainerFactory(globalTemplate_);
    objectFactory->setEventContainerFactory(eventFactory);
    onSetGetPropertyCallback(&globalTemplate_);
    onSetFunctionCallback(&globalTemplate_);
    g_rootTemplate = ObjectTemplate::New();
    context_ = Context::New(NULL, g_rootTemplate);
    forceSetValue(context_->Global());
    context_->Global()->SetHiddenValue(String::New("globalTemplate_"), External::New(&globalTemplate_));
    context_->Global()->SetHiddenValue(String::New("context_"), External::New(&context_));
    setTiObjectToJsObject(context_->Global(), this);
    Context::Scope context_scope(context_);
    initializeTiObject(NULL);
    bool scriptHasError = false;

    const char* bootstrapFilename = "bootstrap.js";
    string bootstrapJavascript;
    {
        ifstream ifs((string("app/native/framework/") + bootstrapFilename).c_str());
        if (!ifs)
        {
            TiLogger::getInstance().log(Ti::Msg::ERROR__Cannot_load_bootstrap_js);
            return -1;
        }
        getline(ifs, bootstrapJavascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    TryCatch tryCatch;
    Handle<Script> compiledBootstrapScript = Script::Compile(String::New(bootstrapJavascript.c_str()), String::New(bootstrapFilename));
    if (compiledBootstrapScript.IsEmpty())
    {
        String::Utf8Value error(tryCatch.Exception());
        TiLogger::getInstance().log(*error);
        return -1;
    }
    Handle<Value> bootstrapResult = compiledBootstrapScript->Run();
    if (bootstrapResult.IsEmpty())
    {
        Local<Value> exception = tryCatch.Exception();
        // FIXME: need a way to prevent double "filename + line" output
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << bootstrapFilename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber();
        }
        ss << ": " << *String::Utf8Value(exception);
        TiLogger::getInstance().log(ss.str().c_str());
        return -1;
    }

    const char* filename = "app.js";
    Handle<Script> compiledScript = Script::Compile(String::New(javaScript), String::New(filename));
    string err_msg;
    if (compiledScript.IsEmpty())
    {
        ReportException(tryCatch, true, err_msg);
        return 1;
    }
    compiledScript->Run();
    if (tryCatch.HasCaught())
    {
        ReportException(tryCatch, true, err_msg);
        scriptHasError = true;
    }

    // show script error
    QString deployType = defaultSettings.value("deploytype").toString();
    if (scriptHasError && deployType.compare(QString("development")) == 0) {

		// clean up display data
		size_t start_pos = 0;
		while((start_pos = err_msg.find("\n", start_pos)) != std::string::npos) {
			err_msg.replace(start_pos, 1, "\\n");
		}

		start_pos = 0;
		while((start_pos = err_msg.find("'", start_pos)) != std::string::npos) {
			err_msg.erase(start_pos, 1);
		}

    	static const string javaScriptErrorAlert = string("var win1 = Titanium.UI.createWindow({") +
											   string("backgroundColor:'red'") +
											   string("});") +
											   string("var label1 = Titanium.UI.createLabel({") +
											   string("color:'#61f427',") +
											   string("textAlign:'center',") +
											   string("text:") +
											   "'" + err_msg + "'," +
											   //string("font:{fontSize:8,fontFamily:'Helvetica Neue',fontStyle:'italic'},") +
											   string("});") +
											   string("win1.add(label1);") +
											   string("win1.open();");


    	compiledScript = Script::Compile(String::New(javaScriptErrorAlert.c_str()));
    	compiledScript->Run();
    }

    onStartMessagePump();
    return (messageLoopEntry)(context);
}

Handle<Object> TiRootObject::createProxyObject()
{
    return globalTemplate_->NewInstance();
}

void TiRootObject::createStringMethods()
{
    Local<Value> str = context_->Global()->Get(String::New("String"));
    if (!str->IsObject())
    {
        // This should never happen<commit_msg>updated text color<commit_after>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "TiRootObject.h"

#include "NativeStringInterface.h"
#include "TiGenericFunctionObject.h"
#include "TiLocaleObject.h"
#include "TiLogger.h"
#include "TiMessageStrings.h"
#include "TiTitaniumObject.h"
#include "TiTimeoutManager.h"
#include "TiV8EventContainerFactory.h"
#include "V8Utils.h"
#include <QSettings>

#include <fstream>
#include <sstream>

#include <QString>
#include <QUrl>

#include <unistd.h>

using namespace titanium;

static Handle<ObjectTemplate> g_rootTemplate;
static const string rootFolder = "app/native/assets/";

// Application properties defined at compile in tiapp.xml
// can be read using this settings instance. It is read only.
static QSettings defaultSettings("app/native/assets/app_properties.ini",
                                 QSettings::IniFormat);

TiRootObject::TiRootObject()
    : TiObject("")
{
}

TiRootObject::~TiRootObject()
{
    if (!context_.IsEmpty())
    {
        context_.Dispose();
    }
    NativeStringInterface::deleteInstance();
}

void TiRootObject::onCreateStaticMembers()
{
    TiObject* ti = TiTitaniumObject::createObject(objectFactory_);
    addMember(ti);
    addMember(ti, "Ti");

    createStringMethods();
    TiGenericFunctionObject::addGenericFunctionToParent(this, "L", this, _L);   // TODO: use the same object as Ti.Locale.getString
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearInterval", this, _clearInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearTimeout", this, _clearTimeout);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "globalRequire", this, _globalRequire);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setInterval", this, _setInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setTimeout", this, _setTimeout);
}

VALUE_MODIFY TiRootObject::onChildValueChange(TiObject* childObject, Handle<Value>, Handle<Value> newValue)
{
    Local<Object> obj = getValue()->ToObject();
    obj->Set(String::New(childObject->getName()), newValue);
    return VALUE_MODIFY_ALLOW;
}

void TiRootObject::addMember(TiObject* object, const char* name)
{
    TiObject::addMember(object, name);
    if (name == NULL)
    {
        name = object->getName();
    }
    Handle<Object> obj = getValue()->ToObject();
    Handle<Value> newValue = object->getValue();
    if (newValue.IsEmpty())
    {
        newValue = globalTemplate_->NewInstance();
        object->forceSetValue(newValue);
        TiObject::setTiObjectToJsObject(newValue, object);
    }
    obj->Set(String::New(name), newValue);
}

TiRootObject* TiRootObject::createRootObject()
{
    TiRootObject* obj = new TiRootObject;
    return obj;
}

int TiRootObject::executeScript(NativeObjectFactory* objectFactory, const char* javaScript,
                                MESSAGELOOPENTRY messageLoopEntry, void* context)
{
    HandleScope handleScope;
    objectFactory_ = objectFactory;
    globalTemplate_ = ObjectTemplate::New();
    TiV8EventContainerFactory* eventFactory = TiV8EventContainerFactory::createEventContainerFactory(globalTemplate_);
    objectFactory->setEventContainerFactory(eventFactory);
    onSetGetPropertyCallback(&globalTemplate_);
    onSetFunctionCallback(&globalTemplate_);
    g_rootTemplate = ObjectTemplate::New();
    context_ = Context::New(NULL, g_rootTemplate);
    forceSetValue(context_->Global());
    context_->Global()->SetHiddenValue(String::New("globalTemplate_"), External::New(&globalTemplate_));
    context_->Global()->SetHiddenValue(String::New("context_"), External::New(&context_));
    setTiObjectToJsObject(context_->Global(), this);
    Context::Scope context_scope(context_);
    initializeTiObject(NULL);
    bool scriptHasError = false;

    const char* bootstrapFilename = "bootstrap.js";
    string bootstrapJavascript;
    {
        ifstream ifs((string("app/native/framework/") + bootstrapFilename).c_str());
        if (!ifs)
        {
            TiLogger::getInstance().log(Ti::Msg::ERROR__Cannot_load_bootstrap_js);
            return -1;
        }
        getline(ifs, bootstrapJavascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    TryCatch tryCatch;
    Handle<Script> compiledBootstrapScript = Script::Compile(String::New(bootstrapJavascript.c_str()), String::New(bootstrapFilename));
    if (compiledBootstrapScript.IsEmpty())
    {
        String::Utf8Value error(tryCatch.Exception());
        TiLogger::getInstance().log(*error);
        return -1;
    }
    Handle<Value> bootstrapResult = compiledBootstrapScript->Run();
    if (bootstrapResult.IsEmpty())
    {
        Local<Value> exception = tryCatch.Exception();
        // FIXME: need a way to prevent double "filename + line" output
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << bootstrapFilename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber();
        }
        ss << ": " << *String::Utf8Value(exception);
        TiLogger::getInstance().log(ss.str().c_str());
        return -1;
    }

    const char* filename = "app.js";
    Handle<Script> compiledScript = Script::Compile(String::New(javaScript), String::New(filename));
    string err_msg;
    if (compiledScript.IsEmpty())
    {
        ReportException(tryCatch, true, err_msg);
        return 1;
    }
    compiledScript->Run();
    if (tryCatch.HasCaught())
    {
        ReportException(tryCatch, true, err_msg);
        scriptHasError = true;
    }

    // show script error
    QString deployType = defaultSettings.value("deploytype").toString();
    if (scriptHasError && deployType.compare(QString("development")) == 0) {

		// clean up display data
		size_t start_pos = 0;
		while((start_pos = err_msg.find("\n", start_pos)) != std::string::npos) {
			err_msg.replace(start_pos, 1, "\\n");
		}

		start_pos = 0;
		while((start_pos = err_msg.find("'", start_pos)) != std::string::npos) {
			err_msg.erase(start_pos, 1);
		}

    	static const string javaScriptErrorAlert = string("var win1 = Titanium.UI.createWindow({") +
											   string("backgroundColor:'red'") +
											   string("});") +
											   string("var label1 = Titanium.UI.createLabel({") +
											   string("color:'white',") +
											   string("textAlign:'center',") +
											   string("text:") +
											   "'" + err_msg + "'," +
											   string("font:{fontSize:8,fontFamily:'Helvetica Neue',fontStyle:'Bold'},") +
											   string("});") +
											   string("win1.add(label1);") +
											   string("win1.open();");


    	compiledScript = Script::Compile(String::New(javaScriptErrorAlert.c_str()));
    	compiledScript->Run();
    }

    onStartMessagePump();
    return (messageLoopEntry)(context);
}

Handle<Object> TiRootObject::createProxyObject()
{
    return globalTemplate_->NewInstance();
}

void TiRootObject::createStringMethods()
{
    Local<Value> str = context_->Global()->Get(String::New("String"));
    if (!str->IsObject())
    {
        // This should never happen
{'fraction_non_alphanumeric': 0.13806399242372996, 'fraction_numerical': 0.004261651897449773, 'mean_word_length': 3.7582877373672354, 'pattern_counts': {'":': 2, '<': 65, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '741778', 'n_tokens_mistral': 4656, 'n_tokens_neox': 4274, 'n_words': 801}