/*
	
 Copyright (c) 2009-2013 Olivier Chafik, All Rights Reserved
 This file is part of JNAerator (http://jnaerator.googlecode.com/).
	
 JNAerator is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
	
 JNAerator is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.
	
 You should have received a copy of the GNU Lesser General Public License
 along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.ochafik.lang.jnaerator;

import java.util.ArrayList;
import java.util.List;

import com.ochafik.lang.jnaerator.parser.Arg;
import com.ochafik.lang.jnaerator.parser.DeclarationsHolder;
import com.ochafik.lang.jnaerator.parser.Declarator;
import com.ochafik.lang.jnaerator.parser.Element;
import com.ochafik.lang.jnaerator.parser.Expression;
import com.ochafik.lang.jnaerator.parser.Function;
import com.ochafik.lang.jnaerator.parser.StoredDeclarations;
import com.ochafik.lang.jnaerator.parser.Declarator.DirectDeclarator;
import com.ochafik.lang.jnaerator.parser.StoredDeclarations.TypeDef;
import com.ochafik.lang.jnaerator.parser.TypeRef;
import com.ochafik.lang.jnaerator.parser.TypeRef.FunctionSignature;
import com.ochafik.lang.jnaerator.parser.TypeRef.TaggedTypeRef;

public class JNAeratorUtils {

    static String getExactTypeDefName(Element e) {
        Element parent = e.getParentElement();
        if (e instanceof FunctionSignature && parent instanceof TypeRef.Pointer) {
            parent = parent.getParentElement();
        }
        if (parent == null || !(parent instanceof TypeDef)) {
            return null;
        }
        TypeDef td = (TypeDef) parent;
        return findBestPlainStorageName(td);
    }

    static List<String> guessOwnerName(Element e) {
        Element parent = e.getParentElement();
        if (parent == null) {
            return null;
        }

//		StoredDeclarations td = as(parent, StoredDeclarations.class);
//		String bestName = JNAeratorUtils.findBestPlainStorageName(td);
//		if (bestName != null)
//			return Arrays.asList(bestName);

        List<String> ns = new ArrayList<String>();

        while (parent != null && !(parent instanceof DeclarationsHolder)) {
            if (parent instanceof Arg) {
                Arg arg = (Arg) parent;
                if (arg.getName() != null) {
                    ns.add(arg.getName());
                }
            } else if (parent instanceof Function) {
                Function f = (Function) parent;
                if (f.getName() != null) {
                    ns.add(0, f.getName().toString());
                }
                return ns;
            } else if (parent instanceof StoredDeclarations) {
                StoredDeclarations sd = (StoredDeclarations) parent;
                String bestName = findBestPlainStorageName(sd);
                if (bestName != null) {
                    ns.add(0, bestName);

                }
            } else if (parent instanceof Expression) {
                if (!ns.contains("expression")) {
                    ns.add("expression");
                }
            }
            parent = parent.getParentElement();
        }
        return ns;

    }

    public static String findBestPlainStorageName(StoredDeclarations sd) {
        if (sd == null) {
            return null;
        }

        TaggedTypeRef ttr = sd.getValueType() instanceof TaggedTypeRef ? (TaggedTypeRef) sd.getValueType() : null;
        String idealName = null;
        if (ttr != null && ttr.getTag() != null) {
            String tn = ttr.getTag().toString();
            if (tn.startsWith("_")) {
                idealName = tn.substring(1);
            } else {
                return tn;
            }
        }
        DirectDeclarator plainDecl = null, idealDecl = null;
        boolean plainHasNiceName = false, hasMoreThanOnePlainDecl = false;
        for (Declarator st : sd.getDeclarators()) {
            if (st instanceof DirectDeclarator) {
                DirectDeclarator decl = (DirectDeclarator) st;
                String name = decl.getName();
                if (name == null) {
                    continue;
                }
                if (name.equals(idealName)) {
                    idealDecl = decl;
                    break;
                }
                boolean hasNiceName = !decl.getName().endsWith("_") && !decl.getName().startsWith("_");
                if (hasMoreThanOnePlainDecl || plainDecl != null && !(!plainHasNiceName && hasNiceName)) {
                    hasMoreThanOnePlainDecl = true;
                    continue;
                }
                plainDecl = decl;
                plainHasNiceName = hasNiceName;
            }
            // TODO play with other names ("pointed_by", "returned_by"...)
        }
        return idealDecl != null ? idealDecl.resolveName()
                : plainDecl != null && !hasMoreThanOnePlainDecl ? plainDecl.resolveName()
                : null;
    }
}
