/*
 * Smart GWT (GWT for SmartClient)
 * Copyright 2008 and beyond, Isomorphic Software, Inc.
 *
 * Smart GWT is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation.  Smart GWT is also
 * available under typical commercial license terms - see
 * http://smartclient.com/license
 *
 * This software 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
 * Lesser General Public License for more details.
 */
/* sgwtgen */
 
package com.smartgwt.client.ai;


import com.smartgwt.client.event.*;
import com.smartgwt.client.core.*;
import com.smartgwt.client.types.*;
import com.smartgwt.client.data.*;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.events.*;
import com.smartgwt.client.browser.window.*;
import com.smartgwt.client.rpc.*;
import com.smartgwt.client.ai.*;
import com.smartgwt.client.callbacks.*;
import com.smartgwt.client.tools.*;
import com.smartgwt.client.bean.*;
import com.smartgwt.client.widgets.*;
import com.smartgwt.client.widgets.ai.*;
import com.smartgwt.client.widgets.events.*;
import com.smartgwt.client.widgets.form.*;
import com.smartgwt.client.widgets.form.validator.*;
import com.smartgwt.client.widgets.form.fields.*;
import com.smartgwt.client.widgets.tile.*;
import com.smartgwt.client.widgets.tile.events.*;
import com.smartgwt.client.widgets.grid.*;
import com.smartgwt.client.widgets.grid.events.*;
import com.smartgwt.client.widgets.chart.*;
import com.smartgwt.client.widgets.layout.*;
import com.smartgwt.client.widgets.layout.events.*;
import com.smartgwt.client.widgets.menu.*;
import com.smartgwt.client.widgets.tour.*;
import com.smartgwt.client.widgets.notify.*;
import com.smartgwt.client.widgets.rte.*;
import com.smartgwt.client.widgets.rte.events.*;
import com.smartgwt.client.widgets.ace.*;
import com.smartgwt.client.widgets.ace.events.*;
import com.smartgwt.client.widgets.tab.*;
import com.smartgwt.client.widgets.toolbar.*;
import com.smartgwt.client.widgets.tree.*;
import com.smartgwt.client.widgets.tree.events.*;
import com.smartgwt.client.widgets.tableview.*;
import com.smartgwt.client.widgets.viewer.*;
import com.smartgwt.client.widgets.calendar.*;
import com.smartgwt.client.widgets.calendar.events.*;
import com.smartgwt.client.widgets.cube.*;
import com.smartgwt.client.widgets.notify.*;
import com.smartgwt.client.widgets.drawing.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.event.shared.*;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.core.client.JavaScriptObject;

import com.smartgwt.client.util.*;
import com.smartgwt.client.util.events.*;
import com.smartgwt.client.util.workflow.*;
import com.smartgwt.client.util.workflow.Process; // required to override java.lang.Process
import com.smartgwt.client.util.tour.*;


/**
 * Provides class methods for enabling and disabling the use of AI technology, registering and unregistering {@link
 * com.smartgwt.client.ai.AIEngine AI engines}, and performing high-level operations using installed AI engines.
 */
@BeanFactory.FrameworkClass
public class AI {


    // ********************* Static Attributes ***********************

    /** 
     * The ID of the default {@link com.smartgwt.client.ai.AIEngine} to use.
     *
     * @param defaultEngineId new defaultEngineId.  Default value is "gpt-4.1".
     */
    public static native void setDefaultEngineId(String defaultEngineId) /*-{
        @com.smartgwt.client.util.JSOHelper::setAttribute(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Ljava/lang/String;)($wnd.isc.AI, "defaultEngineId", defaultEngineId);
    }-*/;

    /** 
     * The ID of the default {@link com.smartgwt.client.ai.AIEngine} to use.
     *
     * @return current value of defaultEngineId
     */
    public static native String getDefaultEngineId() /*-{
        return $wnd.isc.AI.defaultEngineId;
    }-*/;

    /** 
     * The defualt maximum number of retries for any one particular request to AI.
     *
     * @param defaultMaxRetries new defaultMaxRetries.  Default value is 2.
     */
    public static native void setDefaultMaxRetries(int defaultMaxRetries) /*-{
        @com.smartgwt.client.util.JSOHelper::setAttribute(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;I)($wnd.isc.AI, "defaultMaxRetries", defaultMaxRetries);
    }-*/;

    /** 
     * The defualt maximum number of retries for any one particular request to AI.
     *
     * @return current value of defaultMaxRetries
     */
    public static native int getDefaultMaxRetries() /*-{
        var result = $wnd.isc.AI.defaultMaxRetries;
        if (result == null) result = 0;
        return @com.google.gwt.core.client.GWT::isScript()() ? result : result.valueOf(); 
    }-*/;

    /** 
     * Whether AI is disabled. <p> By default, AI is disabled. This static property must be set to <code>false</code> and the
     * {@link com.smartgwt.client.ai.AI#defaultEngineId default} {@link com.smartgwt.client.ai.AIEngine} must be registered in
     * order to enable the use of AI in the application.
     *
     * @param disabled new disabled.  Default value is true.
     */
    public static native void setDisabled(Boolean disabled) /*-{
        @com.smartgwt.client.util.JSOHelper::setAttribute(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Ljava/lang/Boolean;)($wnd.isc.AI, "disabled", disabled);
    }-*/;

    /** 
     * Whether AI is disabled. <p> By default, AI is disabled. This static property must be set to <code>false</code> and the
     * {@link com.smartgwt.client.ai.AI#defaultEngineId default} {@link com.smartgwt.client.ai.AIEngine} must be registered in
     * order to enable the use of AI in the application.
     *
     * @return current value of disabled
     */
    public static native Boolean getDisabled() /*-{
        var result = $wnd.isc.AI.disabled;
        if (result == null) result = null;
        if (!@com.google.gwt.core.client.GWT::isScript()()) result = result.valueOf();
        return @com.smartgwt.client.util.JSOHelper::toBoolean(Z)(result);
    }-*/;

    // ********************* Properties / Attributes ***********************

    // ********************* Methods ***********************

    // ********************* Static Methods ***********************

	/**
     * Asks AI to answer a question about the data of the application.
     * @param question The text of the end-user's question or their request for an answer to a data question.
     */
    public static native void askDataQuestion(String question) /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.askDataQuestion()");
        $wnd.isc.AI.askDataQuestion(question);
    }-*/;

	/**
     * Asks AI to answer a question about the data of the application.
     * @param question The text of the end-user's question or their request for an answer to a data question.
     */
    public static native void askDataQuestion(UserAIRequest question) /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.askDataQuestion()");
        $wnd.isc.AI.askDataQuestion(question.@com.smartgwt.client.core.DataClass::getJsObj()());
    }-*/;

    /**
     * See {@link AI#askDataQuestion(java.lang.String, com.smartgwt.client.data.DataSource[], com.smartgwt.client.ai.DataQuestionSettings, com.smartgwt.client.callbacks.AskDataQuestionResultCallback) askDataQuestion()}
     */
    public static void askDataQuestion(String question, DataSource... dataSources){
        askDataQuestion(question, dataSources, null, null);
    }

    /**
     * See {@link AI#askDataQuestion(com.smartgwt.client.ai.UserAIRequest, com.smartgwt.client.data.DataSource[], com.smartgwt.client.ai.DataQuestionSettings, com.smartgwt.client.callbacks.AskDataQuestionResultCallback) askDataQuestion()}
     */
    public static void askDataQuestion(UserAIRequest question, DataSource... dataSources){
        askDataQuestion(question, dataSources, null, null);
    }
    /**
     * See {@link AI#askDataQuestion(java.lang.String, com.smartgwt.client.data.DataSource[], com.smartgwt.client.ai.DataQuestionSettings, com.smartgwt.client.callbacks.AskDataQuestionResultCallback) askDataQuestion()}
     */
    public static void askDataQuestion(String question, DataSource[] dataSources, DataQuestionSettings settings){
        askDataQuestion(question, dataSources, settings, null);
    }

    /**
     * See {@link AI#askDataQuestion(com.smartgwt.client.ai.UserAIRequest, com.smartgwt.client.data.DataSource[], com.smartgwt.client.ai.DataQuestionSettings, com.smartgwt.client.callbacks.AskDataQuestionResultCallback) askDataQuestion()}
     */
    public static void askDataQuestion(UserAIRequest question, DataSource[] dataSources, DataQuestionSettings settings){
        askDataQuestion(question, dataSources, settings, null);
    }
	/**
     * Asks AI to answer a question about the data of the application.
     * @param question The text of the end-user's question or their request for an answer to a data question.
     * @param dataSources The available data sources. All data sources in the array must have a global ID.  If <code>null</code>, then the array
     * of all DataSources available to the AI module is used.
     * @param settings Settings to use when answering the data question.
     * @param callback The callback to call with the result.
     */
    public static native void askDataQuestion(String question, DataSource[] dataSources, DataQuestionSettings settings, AskDataQuestionResultCallback callback) /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.askDataQuestion()");
        $wnd.isc.AI.askDataQuestion(question, @com.smartgwt.client.util.JSOHelper::convertToJavaScriptArray([Ljava/lang/Object;)(dataSources), settings == null ? null : settings.@com.smartgwt.client.core.DataClass::getJsObj()(), 
			$entry( function(result, dataQuestion) { 
				if(callback!=null) callback.@com.smartgwt.client.callbacks.AskDataQuestionResultCallback::execute(Lcom/smartgwt/client/ai/DataQuestionResult;Lcom/smartgwt/client/ai/DataQuestion;)(
					result != null ? @com.smartgwt.client.ai.DataQuestionResult::new(Lcom/google/gwt/core/client/JavaScriptObject;)(result) : null, 
					dataQuestion != null ? @com.smartgwt.client.ai.DataQuestion::new(Lcom/google/gwt/core/client/JavaScriptObject;)(dataQuestion) : null
				);
			}));
    }-*/;

	/**
     * Asks AI to answer a question about the data of the application.
     * @param question The text of the end-user's question or their request for an answer to a data question.
     * @param dataSources The available data sources. All data sources in the array must have a global ID.  If <code>null</code>, then the array
     * of all DataSources available to the AI module is used.
     * @param settings Settings to use when answering the data question.
     * @param callback The callback to call with the result.
     */
    public static native void askDataQuestion(UserAIRequest question, DataSource[] dataSources, DataQuestionSettings settings, AskDataQuestionResultCallback callback) /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.askDataQuestion()");
        $wnd.isc.AI.askDataQuestion(question.@com.smartgwt.client.core.DataClass::getJsObj()(), @com.smartgwt.client.util.JSOHelper::convertToJavaScriptArray([Ljava/lang/Object;)(dataSources), settings == null ? null : settings.@com.smartgwt.client.core.DataClass::getJsObj()(), 
			$entry( function(result, dataQuestion) { 
				if(callback!=null) callback.@com.smartgwt.client.callbacks.AskDataQuestionResultCallback::execute(Lcom/smartgwt/client/ai/DataQuestionResult;Lcom/smartgwt/client/ai/DataQuestion;)(
					result != null ? @com.smartgwt.client.ai.DataQuestionResult::new(Lcom/google/gwt/core/client/JavaScriptObject;)(result) : null, 
					dataQuestion != null ? @com.smartgwt.client.ai.DataQuestion::new(Lcom/google/gwt/core/client/JavaScriptObject;)(dataQuestion) : null
				);
			}));
    }-*/;


	/**
     * Cancels a data question if not already canceled.
     * @param questionId The ID of the data question to cancel.
     */
    public static native void cancelDataQuestion(String questionId) /*-{
        $wnd.isc.AI.cancelDataQuestion(questionId);
    }-*/;


	/**
     * Returns the {@link com.smartgwt.client.ai.AIEngine} having the given engine ID.
     *
     * @return the <code>AIEngine</code>, or <code>null</code> if the <code>AIEngine</code> could not be found.
     */
    public static native AIEngine getEngine() /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.getEngine()");
        var ret = $wnd.isc.AI.getEngine();
        if(ret == null) return null;
        return @com.smartgwt.client.ai.AIEngine::getOrCreateRef(Lcom/google/gwt/core/client/JavaScriptObject;)(ret);
    }-*/;

	/**
     * Returns the {@link com.smartgwt.client.ai.AIEngine} having the given engine ID.
     * @param engineId the engineId of the <code>AIEngine</code> to get. If not specified, {@link com.smartgwt.client.ai.AI#defaultEngineId
     * defaultEngineId} is used.
     *
     * @return the <code>AIEngine</code>, or <code>null</code> if the <code>AIEngine</code> could not be found.
     */
    public static native AIEngine getEngine(String engineId) /*-{
        @com.smartgwt.client.ai.AI::checkModuleLoaded(Ljava/lang/String;)("call AI.getEngine()");
        var ret = $wnd.isc.AI.getEngine(engineId);
        if(ret == null) return null;
        return @com.smartgwt.client.ai.AIEngine::getOrCreateRef(Lcom/google/gwt/core/client/JavaScriptObject;)(ret);
    }-*/;
	

	/**
     * Determines whether AI support is enabled. {@link com.smartgwt.client.ai.AI#disabled disabled} must be set to
     * <code>false</code> and the default {@link com.smartgwt.client.ai.AIEngine} must be registered in order to enable the use
     * of AI.
     *
     * @return <code>true</code> if the use of AI is enabled; <code>false</code> otherwise.
     * @see com.smartgwt.client.ai.AI#disabled
     * @see com.smartgwt.client.ai.AI#defaultEngineId
     */
    public static native boolean isEnabled() /*-{
        var ret = $wnd.isc.AI.isEnabled();
        return ret == null ? false : ret;
    }-*/;


	/**
     * Pauses a data question if not already paused or canceled.
     * @param questionId The ID of the data question to pause.
     */
    public static native void pauseDataQuestion(String questionId) /*-{
        $wnd.isc.AI.pauseDataQuestion(questionId);
    }-*/;


	/**
     * Registers the given {@link com.smartgwt.client.ai.AIEngine}.
     * @param engine The <code>AIEngine</code> to register.
     *
     * @return <code>true</code> if the <code>AIEngine</code> was successfully registered; <code>false</code> otherwise.
     * @see com.smartgwt.client.ai.AI#unregisterEngine
     */
    public static native boolean registerEngine(AIEngine engine) /*-{
        var ret = $wnd.isc.AI.registerEngine(engine == null ? null : engine.@com.smartgwt.client.core.BaseClass::getOrCreateJsObj()());
        return ret == null ? false : ret;
    }-*/;


	/**
     * Resumes a data question if paused.
     * @param questionId The ID of the data question to resume.
     */
    public static native void resumeDataQuestion(String questionId) /*-{
        $wnd.isc.AI.resumeDataQuestion(questionId);
    }-*/;


	/**
     * Evaluates the given {@link com.smartgwt.client.docs.DynamicStrings dynamic string} to form a prompt string that is then
     * sent as the request to the default AI engine. <p> Within <code>dynamicString</code>, any evaluated JavaScript
     * expressions have access to all of the values in the <code>context</code> ValueMap.
     * @param dynamicString A dynamic string.
     * See {@link com.smartgwt.client.docs.DynamicString DynamicString}
     * @param context A map from each in-scope {@link com.smartgwt.client.docs.Identifier} to its value.
     * @param callback The callback to fire with the response from AI.
     */
    public static native void sendPrompt(String dynamicString, Map context, AIResponseCallback callback) /*-{
        $wnd.isc.AI.sendPrompt(dynamicString, context == null ? null : @com.smartgwt.client.util.JSOHelper::convertMapToJavascriptObject(Ljava/util/Map;)(context), 
			$entry( function(aiResponse, aiRequest) { 
				if(callback!=null) callback.@com.smartgwt.client.callbacks.AIResponseCallback::execute(Lcom/smartgwt/client/ai/AIResponse;Lcom/smartgwt/client/ai/AIRequest;)(
					@com.smartgwt.client.ai.AIResponse::new(Lcom/google/gwt/core/client/JavaScriptObject;)(aiResponse), 
					@com.smartgwt.client.ai.AIRequest::new(Lcom/google/gwt/core/client/JavaScriptObject;)(aiRequest)
				);
			}));
    }-*/;


	/**
     * Unregisters an {@link com.smartgwt.client.ai.AIEngine} specified by its ID.
     * @param engineId the ID of the <code>AIEngine</code> to unregister.
     *
     * @return <code>true</code> if the <code>AIEngine</code> was successfully unregistered; <code>false</code> otherwise.
     * @see com.smartgwt.client.ai.AI#registerEngine
     */
    public static native boolean unregisterEngine(String engineId) /*-{
        var ret = $wnd.isc.AI.unregisterEngine(engineId);
        return ret == null ? false : ret;
    }-*/;


    // ***********************************************************



    /**
     * Reports whether the optional AI module is loaded for the page.
     * @return true if and only if the AI module has been loaded
     */
    public static native boolean moduleLoaded() /*-{
        return $wnd.isc.AI != null;
    }-*/;

    public static void checkModuleLoaded (String faultingAction) {
        if (!moduleLoaded()) {
            String errorMessage = "Attempt to " + faultingAction +
                ".  This requires the optional AI module which is " + 
                (SC.hasAI() ? "not currently loaded." : "not present in this build.");
            SC.logWarn(errorMessage);
            throw new UnsupportedOperationException(errorMessage);
        }
    }


}
