package com.rhomobile.rhodes.osfunctionality;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;

import com.rhomobile.rhodes.Logger;

import android.os.Build;

public class OsVersionManager {
    private static final String TAG = OsVersionManager.class.getSimpleName();
 
    private static OsVersionManager sInstance;
    
    private static OsVersionManager getInstance() {
        if (sInstance == null) {
            sInstance = new OsVersionManager();
        }
        return sInstance;
    }
    
    private OsVersionManager() {
        mActiveFeatures = new HashMap<Class<?>, Object>();
        mSelectors = new ArrayList<HashMap<Class<?>, String>>(Build.VERSION.SDK_INT);
        for(int i = 0; i < Build.VERSION.SDK_INT; ++i) {
            mSelectors.add(new HashMap<Class<?>, String>());
        }
    }
    
    private HashMap<Class<?>, String> selectFeatureMap(int version) {
        Logger.T(TAG, "Select feature map for OS ver. " + version + ", idx: " + (version-1));
        if (version > mSelectors.size()) {
            Logger.W(TAG, "App is built with SDK ver. " + mSelectors.size());
            version = mSelectors.size();
        }
        return mSelectors.get(version - 1);
    }
    
//    private static class Selector<SelectorClass extends Object> {
//        private SelectorClass mSelector;
//        private Class<Object> mClass;
//        Selector(SelectorClass selector, Class<Object> selectorClass) {
//            mSelector = selector;
//            mClass = selectorClass;
//        }
//        Selector(){}
//        SelectorClass getSelector() { return mSelector; }
//        Class<Object> getSelectorClass() { return mClass; }
//    }
    
    private HashMap<Class<?>, Object> mActiveFeatures;
    private ArrayList<HashMap<Class<?>, String>> mSelectors;

    private Object getFeatureInstance(Class<?> selectorIface) {
        Logger.T(TAG, "Looking " + selectorIface);
        return mActiveFeatures.get(selectorIface);
    }
    
    private void setSelector(int version, Class<?> featureIface, String selectorClassName) {
        Logger.T(TAG, "Set " + featureIface + "->" +selectorClassName + " for OS rev. " + version);

        HashMap<Class<?>, String> theVersion = selectFeatureMap(version);
        theVersion.put(featureIface, selectorClassName);

        for (int i = version + 1; i <= Build.VERSION.SDK_INT; ++i) {
            Logger.D(TAG, "Check feature for OS rev. " + i);
            HashMap<Class<?>, String> curVersion = selectFeatureMap(i);
            //if (!curVersion.containsKey(featureIface)) {
                Logger.T(TAG, "OS " + i + ": " + featureIface + "->" + selectorClassName);
                curVersion.put(featureIface, selectorClassName);
            //} else {
            //    break;
            //}
        }
        
        refreshFeature(featureIface);
    }
    
    private void refreshFeature(Class<?> featureIface) {
        Logger.D(TAG, "refreshFeature: " + featureIface);
        String selectorClassName = selectFeatureMap(Build.VERSION.SDK_INT).get(featureIface);
        try {
            Class<?> selectorClass = Class.forName(selectorClassName).asSubclass(featureIface);
            
            Logger.D(TAG, "Set " + featureIface + "->" + selectorClass);
            
            Constructor<?> ctor = selectorClass.getConstructor();
            Object feature = ctor.newInstance();
            
            if (feature == null) {
                Logger.E(TAG, "Cannot create feature instance!");
            } else {
                mActiveFeatures.put(featureIface, feature);
            }
        } catch (Throwable e) {
            Logger.E(TAG, e);
        }
        
    }

    public static void registerSelector(int version, Class<?> featureIface, String selectorClassName) {
        OsVersionManager instance = getInstance();
//        class TheSelector extends Selector<SelectorIface> {
//            TheSelector(SelectorIface selector) {
//                super(selector, (Class<Object>)((ParameterizedType)TheSelector.class.getGenericSuperclass()).getActualTypeArguments()[0]);
//            }
//        }
//        Type selectorType = TheSelector.class.getGenericSuperclass();
//        TypeVariable genType = selectorType.getClass().getTypeParameters()[0];
        
        instance.setSelector(version, featureIface, selectorClassName);
    }
    
    public static void registerSelector(Class<?> featureIface, String selectorClassName) {
        OsVersionManager instance = getInstance();
        instance.setSelector(1, featureIface, selectorClassName);
    }

    public static <SelectorClass> SelectorClass getFeature(Class<?> featureIface) {
        OsVersionManager instance = getInstance();
        
        Object selectorObject = instance.getFeatureInstance(featureIface);
        return (SelectorClass)selectorObject;
    }
    
}

@@ -954,15 +954,8 @@
 G, %22
-Select 
 feat
@@ -965,20 +965,12 @@
  map
- for OS ver.
+: OS
  %22 +
@@ -1065,113 +1065,19 @@
     
-Logger.W(TAG, %22App is built with SDK ver. %22 + mSelectors.size());%0A            version = mSelectors.size()
+return null
 ;%0A  
@@ -2022,37 +2022,88 @@
 G, %22
-Set %22 + featureIface + %22-%3E
+Feature Selector: %22 + featureIface);%0A        Logger.T(TAG, %22Implementation: 
 %22 +
+ 
 sele
@@ -2119,20 +2119,17 @@
 Name + %22
- for
+,
  OS rev.
@@ -2144,32 +2144,34 @@
 sion);%0A%0A        
+//
 HashMap%3CClass%3C?%3E
@@ -2220,24 +2220,66 @@
 rsion);%0A    
+    //if (theVersion != null) %7B%0A        //
     theVersi
@@ -2316,24 +2316,28 @@
 lassName);%0A%0A
+    
         for 
@@ -2356,12 +2356,8 @@
 sion
- + 1
 ; i 
@@ -2393,32 +2393,36 @@
 ) %7B%0A            
+    
 Logger.D(TAG, %22C
@@ -2423,413 +2423,133 @@
 AG, 
-%22Check feature for OS rev. %22 + i);%0A            HashMap%3CClass%3C?%3E, String%3E curVersion = selectFeatureMap(i);%0A            //if (!curVersion.containsKey(featureIface)) %7B%0A                Logger.T(TAG, %22OS %22 + i + %22: %22 + featureIface + %22-%3E%22 + selectorClassName);%0A                curVersion.put(featureIface, selectorClassName);%0A            //%7D else %7B%0A            //    break;%0A            //%7D%0A        %7D%0A        %0A
+selectorClassName + %22 : %22 + i);%0A                selectFeatureMap(i).put(featureIface, selectorClassName);%0A            %7D%0A%0A    
     
@@ -2574,32 +2574,44 @@
 (featureIface);%0A
+        //%7D%0A
     %7D%0A    %0A    p
@@ -2975,30 +2975,8 @@
  %22 +
- featureIface + %22-%3E%22 +
  sel

fix OsVersionManager