/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.hk2.xml.internal.alt.papi;

import java.util.Collections;
import java.util.List;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;

import org.glassfish.hk2.xml.internal.Utilities;
import org.glassfish.hk2.xml.internal.alt.AltAnnotation;
import org.glassfish.hk2.xml.internal.alt.AltClass;
import org.glassfish.hk2.xml.internal.alt.AltMethod;

/**
 * @author jwells
 *
 */
public class ArrayTypeAltClassImpl implements AltClass {
    private final ArrayType arrayType;
    private final ProcessingEnvironment processingEnv;
    private String name;
    private String simpleName;
    
    public ArrayTypeAltClassImpl(ArrayType arrayType, ProcessingEnvironment processingEnv) {
        this.arrayType = arrayType;
        this.processingEnv = processingEnv;
    }
    
    private void calculateNames() {
        StringBuffer sb = new StringBuffer();
        
        TypeMirror currentMirror = arrayType;
        
        int numBraces = 0;
        while (TypeKind.ARRAY.equals(currentMirror.getKind())) {
            sb.append("[");
            
            currentMirror = ((ArrayType) currentMirror).getComponentType();
            
            numBraces++;
        }
        
        // currentMirror is NOT an array
        String lSimpleName;
        if (currentMirror.getKind().isPrimitive()) {
            if (TypeKind.INT.equals(currentMirror.getKind())) {
                sb.append("I");
                lSimpleName = "int";
            }
            else if (TypeKind.LONG.equals(currentMirror.getKind())) {
                sb.append("J");
                lSimpleName = "long";
            }
            else if (TypeKind.BYTE.equals(currentMirror.getKind())) {
                sb.append("B");
                lSimpleName = "byte";
            }
            else if (TypeKind.BOOLEAN.equals(currentMirror.getKind())) {
                sb.append("Z");
                lSimpleName = "boolean";
            }
            else if (TypeKind.CHAR.equals(currentMirror.getKind())) {
                sb.append("C");
                lSimpleName = "char";
            }
            else if (TypeKind.DOUBLE.equals(currentMirror.getKind())) {
                sb.append("D");
                lSimpleName = "double";
            }
            else if (TypeKind.FLOAT.equals(currentMirror.getKind())) {
                sb.append("F");
                lSimpleName = "float";
            }
            else if (TypeKind.SHORT.equals(currentMirror.getKind())) {
                sb.append("S");
                lSimpleName = "short";
            }
            else {
                throw new AssertionError("Unknown primitive type " + currentMirror.getKind() + " for array " + arrayType);
            }
        }
        else if (TypeKind.DECLARED.equals(currentMirror.getKind())) {
            AltClass ac = Utilities.convertTypeMirror(currentMirror, processingEnv);
            
            sb.append("L" + ac.getName() + ";");
            
            lSimpleName = ac.getSimpleName();
        }
        else {
            throw new AssertionError("Unknown array type: " + currentMirror.getKind() + " for array " + arrayType);
        }
        
        name = sb.toString();
        
        StringBuffer simpleNameSB = new StringBuffer(lSimpleName);
        for (int lcv = 0; lcv < numBraces; lcv++) {
            simpleNameSB.append("[]");
        }
        
        simpleName = simpleNameSB.toString();
        
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#getName()
     */
    @Override
    public synchronized String getName() {
        if (name != null) return name;
        
        calculateNames();
        
        return name;
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#getSimpleName()
     */
    @Override
    public synchronized String getSimpleName() {
        if (simpleName != null) return simpleName;
        
        calculateNames();
        
        return simpleName;
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#getAnnotations()
     */
    @Override
    public List<AltAnnotation> getAnnotations() {
        return Collections.emptyList();
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#getMethods()
     */
    @Override
    public List<AltMethod> getMethods() {
        return Collections.emptyList();
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#isInterface()
     */
    @Override
    public boolean isInterface() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#isArray()
     */
    @Override
    public boolean isArray() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.xml.internal.alt.AltClass#getComponentType()
     */
    @Override
    public AltClass getComponentType() {
        TypeMirror compTypeAsMirror = arrayType.getComponentType();
        
        return Utilities.convertTypeMirror(compTypeAsMirror, processingEnv);
    }

}
