package com.axellience.vuegwt.client.jsnative;

import com.axellience.vuegwt.client.VueComponent;
import com.axellience.vuegwt.client.VueComponentFactory;
import com.axellience.vuegwt.client.VueDirective;
import com.axellience.vuegwt.client.definitions.VueComponentDefinition;
import com.axellience.vuegwt.client.definitions.VueDirectiveDefinition;
import com.axellience.vuegwt.client.jsnative.types.JsObject;
import com.axellience.vuegwt.client.jsnative.vue.VueConfig;
import com.google.gwt.dom.client.Element;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;

import static com.axellience.vuegwt.client.definitions.VueDefinitionCache.getComponentDefinitionForClass;
import static com.axellience.vuegwt.client.definitions.VueDefinitionCache.getDirectiveDefinitionForClass;

/**
 * JsInterop representation of the main Vue instance
 * Provide some methods that are specific to VueGWT
 * @author Adrien Baron
 */
@JsType(isNative = true, namespace = JsPackage.GLOBAL)
public class Vue
{
    public static VueConfig config;

    /**
     * Create a VueComponent instance and attach it to a DOM element
     * Equivalent to new Vue({el: element, ...}) in Vue.js
     * @param vueComponentClass The class of the Component to create
     */
    @JsOverlay
    public static <T extends VueComponent> T attach(String element, Class<T> vueComponentClass)
    {
        VueComponentDefinition componentDefinition =
            getComponentDefinitionForClass(vueComponentClass);
        componentDefinition.setEl(element);

        return VueGwtTools.createVueInstance(componentDefinition);
    }

    /**
     * Create a VueComponent instance and attach it to a DOM element
     * Equivalent to new Vue({el: element, ...}) in Vue.js
     * @param vueComponentClass The class of the Component to create
     */
    @JsOverlay
    public static <T extends VueComponent> T attach(Element element, Class<T> vueComponentClass)
    {
        VueComponentDefinition componentDefinition =
            getComponentDefinitionForClass(vueComponentClass);
        componentDefinition.setEl(element);

        return VueGwtTools.createVueInstance(componentDefinition);
    }

    /**
     * Extend the base Vue Class with your VueComponent definition
     * Equivalent to Vue.extend({}) in Vue.js
     * @param vueComponentClass The class of the Component to use
     * @return A factory that can be used to create instance of your VueComponent
     */
    @JsOverlay
    public static <T extends VueComponent> VueComponentFactory<T> extend(Class<T> vueComponentClass)
    {
        JsObject extendedVueClass = extend(getComponentDefinitionForClass(vueComponentClass));
        return new VueComponentFactory<>(extendedVueClass);
    }

    /**
     * Register a component globally
     * It will be usable in any component of your app.
     * @param id Register under the given id
     * @param vueComponentClass The class of the Component to
     */
    @JsOverlay
    public static void component(String id, Class<? extends VueComponent> vueComponentClass)
    {
        Vue.component(id, getComponentDefinitionForClass(vueComponentClass));
    }

    /**
     * Register a component globally
     * It will be usable in any component of your app.
     * The name will be automatically computed based on the component class name
     */
    @JsOverlay
    public static VueComponentFactory component(String id)
    {
        JsObject extendedVueClass = getRegisteredComponent(id);
        return new VueComponentFactory(extendedVueClass);
    }

    /**
     * Register a component globally
     * It will be usable in any component of your app.
     * The name will be automatically computed based on the component class name
     * @param vueComponentClass The class of the Component to register
     */
    @JsOverlay
    public static void component(Class<? extends VueComponent> vueComponentClass)
    {
        Vue.component(VueGwtTools.componentToTagName(vueComponentClass),
            getComponentDefinitionForClass(vueComponentClass));
    }

    /**
     * Register a directive globally
     * It will be usable in any component of your app.
     * The name will be automatically computed based on the directive class name
     * @param vueDirectiveClass The class of the Directive to register
     */
    @JsOverlay
    public static void directive(Class<? extends VueDirective> vueDirectiveClass)
    {
        Vue.directive(VueGwtTools.directiveToTagName(vueDirectiveClass),
            getDirectiveDefinitionForClass(vueDirectiveClass));
    }

    public static native void component(String id, VueComponentDefinition componentDefinition);

    public static native void directive(String name, VueDirectiveDefinition directiveDefinition);

    private static native JsObject extend(VueComponentDefinition componentDefinition);

    @JsMethod(name = "component")
    private static native JsObject getRegisteredComponent(String id);
}

@@ -2807,32 +2807,495 @@
 eClass);%0A    %7D%0A%0A
+    /**%0A     * Register a component globally%0A     * It will be usable in any component of your app.%0A     * The name will be automatically computed based on the component class name%0A     * @param vueComponentClass The class of the Component to register%0A     */%0A    @JsOverlay%0A    public static void component(Class%3C? extends VueComponent%3E vueComponentClass)%0A    %7B%0A        Vue.component(VueGwtTools.componentToTagName(vueComponentClass), vueComponentClass);%0A    %7D%0A%0A
     /**%0A     * R
@@ -3713,171 +3713,60 @@
 * Re
-gister a component globally%0A     * It will be usable in any component of your app.%0A     * The name will be automatically computed based on the component class name
+turn the factory for a given registered component ID
 %0A   
@@ -4001,33 +4001,33 @@
  Register a 
-component
+directive
  globally%0A  
@@ -4135,33 +4135,33 @@
 ased on the 
-component
+directive
  class name%0A
@@ -4173,33 +4173,33 @@
 * @param vue
-Component
+Directive
 Class The cl
@@ -4205,33 +4205,33 @@
 lass of the 
-Component
+Directive
  to register
@@ -4273,33 +4273,33 @@
 static void 
-component
+directive
 (Class%3C? ext
@@ -4306,39 +4306,39 @@
 ends Vue
-Component%3E vueComponent
+Directive%3E vueDirective
 Class)%0A 
@@ -4350,33 +4350,33 @@
         Vue.
-component
+directive
 (VueGwtTools
@@ -4372,33 +4372,33 @@
 VueGwtTools.
-component
+directive
 ToTagName(vu
@@ -4402,87 +4402,43 @@
 (vue
-ComponentClass),%0A            getComponentDefinitionForClass(vueComponent
+DirectiveClass), vueDirective
 Class)
-)
 ;%0A  
@@ -4553,76 +4553,44 @@
   * 
-The name will be automatically computed based on the directive class
+@param name Register under the given
  nam
@@ -4710,32 +4710,45 @@
  void directive(
+String name, 
 Class%3C? extends 
@@ -4812,70 +4812,13 @@
 ive(
-VueGwtTools.directiveToTagName(vueDirectiveClass),%0A           
+name,
  get
@@ -4874,29 +4874,30 @@
     %7D%0A%0A    p
-ublic
+rivate
  static nati
@@ -4972,29 +4972,30 @@
 ion);%0A%0A    p
-ublic
+rivate
  static nati

Add a method to register a directive globally with a custom name