import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Gère une méthode.
 * @author V.BOULANGER
 */
public class Method implements Serializable {

    public static int _methodId = 0;
    public static final String PRIVATE = "-";
    public static final String PROTECTED = "#";
    public static final String PUBLIC = "+";

    private int _id;
    private String _access;
    private String _type;
    private String _name;
    private List<Argument> _arguments;
    private boolean _isConstructor;
    private boolean _isStatic;
    private boolean _isFinal;
    private boolean _isAbstract;
    private boolean _isSynchronized;
    private boolean _isVolatile;
    private boolean _isTransient;

    /**
     * Constructeur - Crée une instance de Method.
     */
    public Method(){
        _methodId++;
        this._id = _methodId;
        this._access = Method.PUBLIC;
        this._type = "void";
        this._name = "method" + this._id;
        this._arguments = new ArrayList<Argument>();
    }

    /**
     * Constructeur - Crée une instance de Method avec des paramètres donnés.
     * @param access Le modificateur d'accès de la méthode.
     * @param type Le type de la méthode.
     * @param name Le nom de la méthode.
     * @param arguments Les arguments de la méthode.
     */
    public Method(String access, String type, String name, ArrayList<Argument> arguments){
        _methodId++;
        this._id = _methodId;
        this._access = access;
        this._type = type;
        this._name = name;
        this._arguments = arguments;
    }

    /**
     * Constructeur - Crée une instance de Method avec des paramètres donnés.
     * @param access Le modificateur d'accès de la méthode.
     * @param type Le type de la méthode.
     * @param name Le nom de la méthode.
     * @param arguments Les arguments de la méthode.
     * @param constr Si la méthode est un constructeur.
     * @param stat Si la méthode est statique.
     * @param fina Si la méthode est finale.
     * @param abst Si la méthode est abstraite.
     * @param sync Si la méthode est synchronisée.
     * @param vola Si la méthode est volatile.
     * @param tran Si la méthode est transitoire.
     */
    public Method(String access, String type, String name, List<Argument> arguments, boolean constr, boolean stat, boolean fina, boolean abst, boolean sync, boolean vola, boolean tran){
        _methodId++;
        this._id = _methodId;
        this._access = access;
        this._type = type;
        this._name = name;
        this._arguments = arguments;
        this._isConstructor = constr;
        this._isStatic = stat;
        this._isFinal = fina;
        this._isAbstract = abst;
        this._isSynchronized = sync;
        this._isVolatile = vola;
        this._isTransient = tran;
    }

    /**
     * Récupère le numéro de la méthode.
     * @return Le numéro de la méthode.
     */
    public int getId() {
        return _id;
    }

    /**
     * Récupère le modificateur d'accès de la méthode.
     * @return Le modificateur d'accès de la méthode.
     */
    public String getAccess() {
        return _access;
    }

    /**
     * Paramètre le modificateur d'accès de la méthode.
     * @param access Le modificateur d'accès de la méthode.
     */
    public void setAccess(String access) {
        this._access = access;
    }

    /**
     * Récupère le type de la méthode.
     * @return Le type de la méthode.
     */
    public String getType() {
        return _type;
    }

    /**
     * Paramètre le type de la méthode.
     * @param type Le type de la méthode.
     */
    public void setType(String type) {
        this._type = type;
    }

    /**
     * Récupère le nom de la méthode.
     * @return Le nom de la méthode.
     */
    public String getName() {
        return _name;
    }

    /**
     * Paramètre le nom de la méthode.
     * @param name Le nom de la méthode.
     */
    public void setName(String name) {
        this._name = name;
    }

    /**
     * Récupère tous les arguments de la méthode.
     * @return Les arguments de la méthode.
     */
    public List<Argument> getArguments() {
        return _arguments;
    }

    /**
     * Ajoute un argument à la méthode.
     * @param a L'argument à ajouter.
     */
    public void addArgument(Argument a){
        this._arguments.add(a);
    }

    /**
     * Retire un argument de la méthode.
     * @param index L'index de l'argument à retirer.
     */
    public void removeArgument(int index){
        this._arguments.remove(index);
    }

    /**
     * Retire tous les arguments de la méthode.
     */
    public void clearArguments(){
        this._arguments.clear();
    }

    /**
     * Faire remonter l'argument sélectionné dans la liste.
     * @param index L'index de l'argument concerné.
     * @return true if succeed, false if failed
     */
    public boolean upArgument(int index){
        int argNumber = this._arguments.size();
        //Si au moins 2 arguments et que l'argument n'est pas en 1ère position, on le remonte
        if(index != 0 && argNumber > 1){
            Collections.swap(_arguments, index, index - 1);
            return true;
        }
        return false;
    }

    /**
     * Faire descendre l'argument sélectionné dans la liste.
     * @param index L'index de l'argument concerné.
     * @return true if succeed, false if failed
     */
    public boolean downArgument(int index){
        int argNumber = this._arguments.size();
        //Si au moins 2 arguments et que l'argument n'est pas en dernière position, on le descend
        if(index != argNumber - 1 && argNumber > 1){
            Collections.swap(_arguments, index, index + 1);
            return true;
        }
        return false;
    }

    /**
     * Retourne si la méthode est un constructeur de la classe.
     * @return true : la méthode est un constructeur, false: la méthode n'est pas un constructeur.
     */
    public boolean isConstructor(){
        return _isConstructor;
    }

    /**
     * Paramètre la caractéristique de constructeur de la méthode.
     * @param c true : la méthode est un constructeur, false: la méthode n'est pas un constructeur.
     */
    public void setConstructor(boolean c){
        _isConstructor = c;
    }

    /**
     * Retourne si la méthode est statique ou non.
     * @return true : la méthode est statique, false: la méthode n'est pas statique.
     */
    public boolean isStatic() {
        return _isStatic;
    }

    /**
     * Paramètre la caractéristique statique de la méthode.
     * @param s true : la méthode est statique, false : la méthode n'est pas statique
     */
    public void setStatic(boolean s) {
        this._isStatic = s;
    }

    /**
     * Retourne si la méthode est final ou non.
     * @return true : la méthode est final, false: la méthode n'est pas final.
     */
    public boolean isFinal() {
        return _isFinal;
    }

    /**
     * Paramètre la caractéristique final de la méthode.
     * @param f true : la méthode est final, false : la méthode n'est pas final
     */
    public void setFinal(boolean f) {
        this._isFinal = f;
    }

    /**
     * Retourne si la méthode est abstrait ou non.
     * @return true : la méthode est abstrait, false: la méthode n'est pas abstrait.
     */
    public boolean isAbstract() {
        return _isAbstract;
    }

    /**
     * Paramètre la caractéristique abstraite de la méthode.
     * @param a true : la méthode est abstrait, false : la méthode n'est pas abstrait.
     */
    public void setAbstract(boolean a) {
        this._isAbstract = a;
    }

    /**
     * Retourne si la méthode est synchronisé ou non.
     * @return true : v est synchronisé, false: la méthode n'est pas synchronisé.
     */
    public boolean isSynchronized() {
        return _isSynchronized;
    }

    /**
     * Paramètre la caractéristique synchronisée de la méthode.
     * @param s true : la méthode est synchronisé, false : la méthode n'est pas synchronisé.
     */
    public void setSynchronized(boolean s) {
        this._isSynchronized = s;
    }

    /**
     * Retourne si la méthode est volatile ou non.
     * @return true : la méthode est volatile, false: la méthode n'est pas volatile.
     */
    public boolean isVolatile() {
        return _isVolatile;
    }

    /**
     * Paramètre la caractéristique volatile de la méthode.
     * @param v true : la méthode est volatile, false : la méthode n'est pas volatile
     */
    public void setVolatile(boolean v) {
        this._isVolatile = v;
    }

    /**
     * Retourne si la méthode est transitoire ou non.
     * @return true : la méthode est transitoire, false: la méthode n'est pas transitoire.
     */
    public boolean isTransient() {
        return _isTransient;
    }

    /**
     * Paramètre la caractéristique transitoire de la méthode.
     * @param t true : la méthode est transitoire, false : la méthode n'est pas transitoire
     */
    public void setTransient(boolean t) {
        this._isTransient = t;
    }
}
