/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.weex.ui.config;

import android.text.TextUtils;
import android.util.Pair;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.weex.WXEnvironment;
import org.apache.weex.WXSDKInstance;
import org.apache.weex.WXSDKManager;
import org.apache.weex.bridge.Invoker;
import org.apache.weex.ui.ComponentCreator;
import org.apache.weex.ui.IFComponentHolder;
import org.apache.weex.ui.SimpleComponentHolder;
import org.apache.weex.ui.action.BasicComponentData;
import org.apache.weex.ui.component.WXComponent;
import org.apache.weex.ui.component.WXVContainer;
import org.apache.weex.utils.WXLogUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * Created by furture on 2018/2/7.
 */
public class ConfigComponentHolder implements IFComponentHolder {


    public static final String TAG = AutoScanConfigRegister.TAG;
    private Map<String, Invoker> mPropertyInvokers;
    private Map<String, Invoker> mMethodInvokers;

    private ClassLoader mClassLoader;

    private String mType;
    private boolean mAppendTree;
    private String mClassName;
    private String[] methods;
    private Class mClass;

    public ConfigComponentHolder(String mType, boolean mAppendTree, String mClassName, String[] methods) {
        this.mType = mType;
        this.mAppendTree = mAppendTree;
        this.mClassName = mClassName;
        this.methods = methods;
    }

    @Override
    public void loadIfNonLazy() {
    }

    private synchronized boolean generate(){
        if(mClass == null){
            return false;
        }

        Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = SimpleComponentHolder.getMethods(mClass);
        mPropertyInvokers = methodPair.first;
        mMethodInvokers = methodPair.second;
        return true;
    }



    @Override
    public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        if(mClass == null || mClassLoader != instance.getContext().getClassLoader()){
            mClass = WXSDKManager
                .getInstance().getClassLoaderAdapter().getComponentClass(mType, mClassName, instance);
            mClassLoader = instance.getContext().getClassLoader();
        }
        ComponentCreator creator = new SimpleComponentHolder.ClazzComponentCreator(mClass);
        WXComponent component = creator.createInstance(instance, parent, basicComponentData);

        component.bindHolder(this);
        return component;
    }

    @Override
    public synchronized Invoker getPropertyInvoker(String name){
        if (mPropertyInvokers == null && !generate()) {
            return null;
        }

        return mPropertyInvokers.get(name);
    }

    @Override
    public Invoker getMethodInvoker(String name) {
        if(mMethodInvokers == null && !generate()){
            return null;
        }
        return mMethodInvokers.get(name);
    }

    @Override
    public String[] getMethods() {
        if(methods == null){
            //generate failed
            return new String[0];
        }
        return methods;
    }


    public static final ConfigComponentHolder fromConfig(JSONObject config){
        if(config == null){
            return null;
        }
        try{
            String type = config.getString("name");
            boolean appendTree  = config.getBooleanValue("appendTree");
            String className = config.getString("className");
            JSONArray methods =  null;
            if(config.containsKey("methods")) {
                methods = config.getJSONArray("methods");
            }
            if(TextUtils.isEmpty(type) || TextUtils.isEmpty(className)){
                return null;
            }
            String[]  arrays = new String[0];
            if(methods != null){
                arrays = new String[methods.size()];
                methods.toArray(arrays);
            }
            if(WXEnvironment.isApkDebugable()){
                WXLogUtils.d(TAG, "resolve component " + type + " className " + className +  " methods " + methods);
            }
            return new ConfigComponentHolder(type, appendTree, className, arrays);
        }catch (Exception e){
            WXLogUtils.e(TAG, e);
            return null;
        }

    }

    public boolean isAppendTree() {
        return mAppendTree;
    }

    public String getType() {
        return mType;
    }
}
