/*******************************************************************************
* Copyright (c) 2006 IONA Technologies PLC
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* 
* Contributors:
*     IONA Technologies PLC - initial API and implementation
*******************************************************************************/
package org.eclipse.stp.sc.common.views;

import java.lang.reflect.Method;
import java.util.Iterator;

import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.stp.common.logging.LoggingProxy;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.StringLiteral;

/**
 * label provider for the <code>TreeViewer</code> of the <code>AnnotationView</code>.
 * this class is not meant to be reused outside this context
 */
class AnnotationViewerLabelProvider implements ITableLabelProvider {
    private static final LoggingProxy LOG = LoggingProxy.getlogger(AnnotationViewerLabelProvider.class);
    
    private AnnotationView parent;
    
    public AnnotationViewerLabelProvider(AnnotationView aParent) {
        parent = aParent;
    }

    public Image getColumnImage(Object element, int columnIndex) {
    	if (columnIndex != 0) return null;
        if (element instanceof Class) {
            return isAnnotationDeclaredForElement((Class)element) ? parent.iconOn : parent.iconOff;
        }
        if (element instanceof Object[]) {
        	Object[] pair = (Object[])element;
        	if (pair[0] instanceof String) {
        		return (((String)pair[0]).indexOf(":Existing") >= 0) ? parent.iconOn : parent.iconOff;
        	}
        }
        return null;
    }

    /**
     * displays the names/labels of the (JSR 181) annotation classes and attributes provided on the 1st column
     *  and then dig the java model to see if they are set for the selected java element and, if found then,
     *  display their value in the 2nd column.
     */
    public String getColumnText(Object element, int columnIndex) {
        if (element instanceof Class) {
            Class annotationClass = (Class)element;

            switch (columnIndex) {
            case 0:
                return annotationClass.getName();

            case 1:
                return "" + isAnnotationDeclaredForElement(annotationClass);

            default:
                return "";
            }
        } else if (element instanceof Method) {
            Method theMethod = (Method)element;

            switch (columnIndex) {
            case 0:
                return theMethod.getName();

            case 1:

                String completeTextValue = getCurrentpropertyValue(theMethod);

                // String and enum values need a bit of editing to render properly
                if ((completeTextValue == null) || completeTextValue.equals("")) {
                    return null;
                }

                if (completeTextValue.startsWith("\"")
                        && completeTextValue.endsWith("\"")
                        && (completeTextValue.length() >= 2)) {
                    return completeTextValue.substring(1, completeTextValue.length() - 1);
                }

                if (completeTextValue.toLowerCase().indexOf(theMethod.getName().toLowerCase() + ".") > -1) {
                    return completeTextValue.substring(1 + completeTextValue.lastIndexOf('.'));
                }

                return completeTextValue;

            default:
                return "";
            }
        } else if (element instanceof Object[]) {
        	Object[] pair = (Object[])element;
        	if (pair[0] instanceof String) {
        		String className = (String)pair[0];
        		int index = className.indexOf(":");
        		className = className.substring(0, index);
        		switch (columnIndex) {
        		case 0:
        			return className;

        		case 1:
        			return "" + (((String)pair[0]).indexOf(":Existing") >= 0);

        		default:
        			return "";
        		}
        	} else if (pair[0] instanceof Method) {
        		Method method = (Method)pair[0];
        		switch (columnIndex) {
        		case 0:
        			return method.getName();

        		case 1:
        			String value = "";
        			if (pair[1] != null) {
        				MemberValuePair mvp = (MemberValuePair)pair[1];
        				Expression expression = mvp.getValue();
        				if (expression instanceof StringLiteral) {
        					StringLiteral sl = (StringLiteral)expression;
        					value = sl.getEscapedValue();
        					value = value.substring(1, value.length() - 1);
        				} else {
        					value = expression.toString();
        				}
        			}
        			return value;

        		default:
        			return "";
        		}
        	}
        }
        return null;
    }

    public void addListener(ILabelProviderListener arg0) {
    }

    public void dispose() {
    }

    public boolean isLabelProperty(Object arg0, String arg1) {
        return false;
    }

    public void removeListener(ILabelProviderListener arg0) {
    }

    /**
     * conveniance method to see if the th annotation represented by the element specified is declared for the
     * java element being processed
     * @param element
     * @return
     */
    private boolean isAnnotationDeclaredForElement(Class annotationClass) {
        return parent.annotationNodesMap.get(annotationClass.getSimpleName()) != null
                || parent.annotationNodesMap.get(annotationClass.getName()) != null;
    }

    /**
     * @return
     */
    @SuppressWarnings("unchecked")
    private String getCurrentpropertyValue(Method attributeAccessor) {
        
        Annotation genericAnnotation;
        String annotationClassName = attributeAccessor.getDeclaringClass().getSimpleName();
        genericAnnotation = parent.annotationNodesMap.get(annotationClassName);
        
        // check the fully qualified name
        if (genericAnnotation == null) {
            annotationClassName = attributeAccessor.getDeclaringClass().getName();
            genericAnnotation = parent.annotationNodesMap.get(annotationClassName);
        }

        if (genericAnnotation == null) {
            return null;
        }

        if (genericAnnotation instanceof NormalAnnotation) {
            NormalAnnotation currentAnnotation = (NormalAnnotation)genericAnnotation;

            for (Iterator<MemberValuePair> iter = currentAnnotation.values().iterator(); iter.hasNext();) {

                MemberValuePair attribute = iter.next();
                LOG.debug("attribute Name : " + attribute.getName());
                LOG.debug("attribute type : " + attribute.getValue().getClass().getCanonicalName());
                LOG.debug("attribute value : " + attribute.getValue().toString());
                if (attribute.getName().getIdentifier().equals(attributeAccessor.getName())) {
                    return attribute.getValue().toString();
                }
            }
        }

        if (genericAnnotation instanceof SingleMemberAnnotation) {
            return ((SingleMemberAnnotation)genericAnnotation).getValue().toString();
        }

        return null;
    }
}
