package be.ibridge.kettle.core.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;

import be.ibridge.kettle.core.Const;

public class StringSearcher
{
    public static final void findMetaData(Object object, int level, List stringList, Object parentObject)
    {
        // System.out.println(Const.rightPad(" ", level)+"Finding strings in "+object.toString());
        
        if (level>5) return;
        
        Class baseClass = object.getClass();
        Field[] fields = baseClass.getDeclaredFields();
        for (int i=0;i<fields.length;i++)
        {
            Field field = fields[i];
            
            boolean processThisOne = true;
            
            if ( (field.getModifiers()&Modifier.FINAL ) > 0) processThisOne=false;
            if ( (field.getModifiers()&Modifier.STATIC) > 0) processThisOne=false;
            if ( field.toString().indexOf("be.ibridge.kettle")<0 ) processThisOne=false; // Stay in this code-base.
            
            if (processThisOne)
            {
                try
                {
                    Object obj = field.get(object);
                    if (obj!=null)
                    {
                        if (obj instanceof String)
                        {
                            // OK, let's add the String
                            stringList.add(new StringSearchResult((String)obj, parentObject, field.getName()));                       
                        }
                        else
                        if (obj instanceof String[])
                        {
                            String[] array = (String[])obj;
                            for (int x=0;x<array.length;x++) 
                            {
                                if (array[x]!=null)
                                {
                                    stringList.add(new StringSearchResult(array[x], parentObject, field.getName()+" #"+(x+1)));
                                }
                            }
                        }
                        else
                        if (obj instanceof Boolean)
                        {
                            // OK, let's add the String
                            stringList.add(new StringSearchResult(((Boolean)obj).toString(), parentObject, field.getName()+" (Boolean)"));                       
                        }
                        else
                        if (obj instanceof Object)
                        {
                            findMetaData(obj, level+1, stringList, parentObject);
                        }
                        else
                        if (obj instanceof Object[])
                        {
                            for (int j=0;j<((Object[])obj).length;j++) findMetaData( ((Object[])obj)[j], level+1, stringList, parentObject);
                        }
                    }
                }
                catch(IllegalAccessException e)
                {
                    // OK, it's private, let's see if we can go there later on using getters and setters...
                    // fileName becomes: getFileName();
                     
                    Method method = findMethod(baseClass, field.getName());
                    if (method!=null)
                    {
                        String fullMethod = baseClass.getName()+"."+method.getName()+"()";
                            
                        // OK, how do we get the value now?
                        try
                        {
                            // System.out.println(Const.rightPad(" ", level)+"  Invoking method: "+fullMethod+", on object: "+object.toString());
                            Object string = method.invoke(object, null);
                            if (string!=null)
                            {
                                if (string instanceof String)
                                {
                                    stringList.add(new StringSearchResult((String)string, parentObject, field.getName()));
                                    // System.out.println(Const.rightPad(" ", level)+"  "+field.getName()+" : method "+fullMethod+" --> "+((String)string));
                                }
                                else
                                if (string instanceof String[])
                                {
                                    String[] array = (String[])string;
                                    for (int x=0;x<array.length;x++) 
                                    {
                                        if (array[x]!=null)
                                        {
                                            stringList.add(new StringSearchResult(array[x], parentObject, field.getName()+" #"+(x+1)));
                                            /// System.out.println(Const.rightPad(" ", level)+"  "+field.getName()+" : method "+fullMethod+" --> String #"+x+" = "+array[x]);
                                        }
                                    }
                                }
                                else
                                if (string instanceof Boolean)
                                {
                                    // OK, let's add the String
                                    stringList.add(new StringSearchResult(((Boolean)string).toString(), parentObject, field.getName()+" (Boolean)"));                       
                                }
                                else
                                if (string instanceof Object[])
                                {
                                    for (int j=0;j<((Object[])string).length;j++) findMetaData( ((Object[])string)[j], level+1, stringList, parentObject);
                                }
                                else
                                if (string instanceof Object) // OK, so it's not a string but an object: go a bit deeper into it!
                                {
                                    findMetaData(string, level+1, stringList, parentObject);
                                }
                            }
                        }
                        catch(Exception ex)
                        {
                            System.out.println(Const.rightPad(" ", level)+"    Unable to get access to method "+fullMethod+" : "+e.toString());
                        }
                    }
                }
            }
        }        
    }

    private static Method findMethod(Class baseClass, String name)
    {
        // baseClass.getMethod(methodName[m], null);
        Method[] methods = baseClass.getDeclaredMethods();
        Method method = null;

        // getName()
        if (method==null)
        {
            String getter = constructGetter(name);
            method = searchGetter(getter, baseClass, methods);
        }

        // isName()
        if (method==null)
        {
            String getter = constructIsGetter(name);
            method = searchGetter(getter, baseClass, methods);
        }

        // name()
        if (method==null)
        {
            String getter = name;
            method = searchGetter(getter, baseClass, methods);
        }
        
        return method;

    }

    private static Method searchGetter(String getter, Class baseClass, Method[] methods)
    {
        Method method =null;
        try
        {
            method=baseClass.getMethod(getter, null);
        }
        catch(Exception e)
        {
            // Nope try case insensitive.
            for (int i=0;i<methods.length;i++)
            {
                String methodName = methods[i].getName(); 
                if (methodName.equalsIgnoreCase(getter))
                {
                    return methods[i];
                }
            }
            
        }
        
        return method;
    }

    public static final String constructGetter(String name)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("get");
        buf.append(name.substring(0,1).toUpperCase());
        buf.append(name.substring(1));
        
        return buf.toString();
    }
    
    public static final String constructIsGetter(String name)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("is");
        buf.append(name.substring(0,1).toUpperCase());
        buf.append(name.substring(1));
        
        return buf.toString();
    }
    
}


@@ -164,24 +164,66 @@
 il.List;%0D%0A%0D%0A
+import be.ibridge.kettle.core.Condition;%0D%0A
 import be.ib
@@ -2566,32 +2566,312 @@
           else%0D%0A
+                        if (obj instanceof Condition)%0D%0A                        %7B%0D%0A                        %09stringList.add(new StringSearchResult(((Condition)obj).toString(), parentObject, field.getName()+%22 (Condition)%22));%0D%0A                        %7D%0D%0A                        else%0D%0A
                 
@@ -6008,32 +6008,358 @@
           else%0D%0A
+                                if (string instanceof Condition)%0D%0A                                %7B%0D%0A                                %09stringList.add(new StringSearchResult(((Condition)string).toString(), parentObject, field.getName()+%22 (Condition)%22));%0D%0A                                %7D%0D%0A                                else%0D%0A
                 

Fix for bug: #2345 Reflection should not go into the condition all the way, calling setNegate by accident!