/*
 * Copyright (c) 2012, the authors.
 *
 *   This file is part of Blow.
 *
 *   Blow is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Blow 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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Blow.  If not, see <http://www.gnu.org/licenses/>.
 */

package blow.util

import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.messages.SyntaxErrorMessage
import org.codehaus.groovy.syntax.SyntaxException

/**
 *
 *  @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
 */
@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
public class SerializableASTTransformation implements ASTTransformation {

    static final def random = new Random()

    public void visit(ASTNode[] nodes, SourceUnit source) {
        if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
            addError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + Arrays.asList(nodes), nodes[0], source);
        }

        AnnotatedNode parent = (AnnotatedNode) nodes[1];
        AnnotationNode serializeAnnotation = (AnnotationNode) nodes[0];


        if (parent instanceof ClassNode) {
            ClassNode classNode = (ClassNode) parent;

            /* Add the Serializable interface */
            classNode.addInterface(ClassHelper.make(java.io.Serializable.class));

            /* Add the serialVersionUID  field */
            def modifier = FieldNode.ACC_PRIVATE | FieldNode.ACC_STATIC | FieldNode.ACC_FINAL
            def value = new ConstantExpression( getVersion(serializeAnnotation), true )

            classNode.addField("serialVersionUID", modifier, ClassHelper.make(Long.TYPE), value)
        }
    }

    private long getVersion( AnnotationNode annotation ) {
        def value = annotation.getMember('ver')?.getText();
        def result = value && value.isLong() ? Long.parseLong(value) : -1

        return result
    }

    public void addError(String msg, ASTNode expr, SourceUnit source) {
        int line = expr.getLineNumber();
        int col = expr.getColumnNumber();
        source.getErrorCollector().addErrorAndContinue(
                new SyntaxErrorMessage(new SyntaxException(msg + '\n', line, col), source)
        );
    }
}