/*******************************************************************************
 * Copyright (c) 2006 IBM Corporation.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.ibm.wala.types.generics;

import java.util.ArrayList;

import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.ShrikeClass;
import com.ibm.wala.shrikeCT.InvalidClassFileException;

/**
 * Under construction.
 * 
 * ClassSignature: 
 *    (<FormalTypeParameter+>)? SuperclassSignature SuperinterfaceSignature*
 * 
 * SuperclassSignature:
 *    ClassTypeSignature
 *    
 * SuperinterfaceSignature:
 *    ClassTypeSignature
 * 
 * @author sjfink
 * 
 */
public class ClassSignature extends Signature {

  private ClassSignature(String sig) {
    super(sig);
  }

  public static ClassSignature make(String sig) {
    if (sig == null || sig.length() == 0) {
      throw new IllegalArgumentException("empty or null sig");
    }
    return new ClassSignature(sig);
  }

  /**
   * @return the formal type parameters, or null if none
   */
  public FormalTypeParameter[] getFormalTypeParameters() {
    if (rawString().charAt(0) != '<') {
      // no formal type parameters
      return null;
    }
    int index = endOfFormalTypeParameters();
    String[] args = FormalTypeParameter.parseForFormalTypeParameters(rawString().substring(0,index));
    FormalTypeParameter[] result = new FormalTypeParameter[args.length];
    for (int i = 0; i < args.length; i++) {
      result[i] = FormalTypeParameter.make(args[i]);
    }
    return result;
  }
  
  public ClassTypeSignature getSuperclassSignature() throws IllegalArgumentException {
    return ClassTypeSignature.makeClassTypeSig(rawString().substring(endOfFormalTypeParameters(),endOfClassTypeSig(endOfFormalTypeParameters())));
  }
  
  private int endOfClassTypeSig(int start) throws IllegalArgumentException {
    String s = rawString().substring(start);
    if (s.charAt(0) != 'L') {
      throw new IllegalArgumentException("malformed ClassSignature " + rawString());
    }
    int i = 1;
    int depth = 0;
    while (depth > 0 || s.charAt(i) != ';') {
      if (s.charAt(i) == '<') {
        depth++;
      }
      if (s.charAt(i) == '>') {
        depth--;
      }
      i++;
    }
    return start + i + 1;
  }
  
  public ClassTypeSignature[] getSuperinterfaceSignatures() throws IllegalArgumentException {
    int start = endOfClassTypeSig(endOfFormalTypeParameters());
    ArrayList<ClassTypeSignature> result = new ArrayList<ClassTypeSignature>();
    while (start < rawString().length() - 1) {
      int end = endOfClassTypeSig(start);
      result.add(ClassTypeSignature.makeClassTypeSig(rawString().substring(start,end)));
      start = end;
    }
    if (result.size() == 0) {
      return null;
    }
    ClassTypeSignature[] arr = new ClassTypeSignature[result.size()];
    return result.toArray(arr);
    
  }
  
  private int endOfFormalTypeParameters() {
    if (rawString().charAt(0) != '<') {
      return 0;
    }
    int i = 1;
    int depth = 1;
    while (depth > 0) {
      if (rawString().charAt(i) == '>') {
        depth--;
      }
      if (rawString().charAt(i) == '<') {
        depth++;
      }
      i++;
    }
    return i;
  }
  
  /**
   * @param klass
   * @return the class signature, or null if none
   * @throws InvalidClassFileException
   */
  public static ClassSignature getClassSignature(IClass klass) throws InvalidClassFileException {
    if (klass instanceof ShrikeClass) {
      ShrikeClass sc = (ShrikeClass) klass;
      return sc.getClassSignature();
    } else {
      return null;
    }
  }
}
