/*
 * $Header: /home/harald/repos/remotetea.sf.net/remotetea/src/org/acplt/oncrpc/apps/jrpcgen/JrpcgenUnionArm.java,v 1.2 2003/08/14 08:09:59 haraldalbrecht Exp $
 *
 * Copyright (c) 1999, 2000
 * Lehrstuhl fuer Prozessleittechnik (PLT), RWTH Aachen
 * D-52064 Aachen, Germany.
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This library 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this program (see the file LICENSE.txt for more
 * details); if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package org.acplt.oncrpc.apps.jrpcgen;

import java.io.IOException;
import java.util.Objects;

/**
 * The <code>JrpcgenUnionArm</code> class represents a single union arm defined
 * for a particular union in an rpcgen "x"-file.
 *
 * @version $Revision: 1.2 $ $Date: 2003/08/14 08:09:59 $ $State: Exp $ $Locker:  $
 * @author Harald Albrecht
 */
public class JrpcgenUnionArm {

    /**
     * Value for which the descriminated union arm is valid.
     */
    public String value;

    /**
     * Attribute element of descriminated arm (of class
     * {@link JrpcgenDeclaration}).
     */
    public JrpcgenDeclaration element;

    /**
     * Constructs a <code>JrpcgenUnionArm</code> and sets decrimated arm's
     * value and the associated attribute element.
     *
     * @param value Value for which descriminated arm is valid.
     * @param element Descriminated arm element of class
     *   {@link JrpcgenDeclaration}.
     */
    public JrpcgenUnionArm(String value,
                           JrpcgenDeclaration element) {
        this.value = value;
        this.element = element;
    }

    public boolean mapsToFollowingArm() {
    	return (element == null);
    }

    public boolean isDefaultArm() {
    	return (value == null);
    }

    public boolean hasVoidType() {
    	return (element != null) && element.getTypeMapping().isVoid();
    }
    
    public boolean hasPayload() {
    	return (element != null) && (! element.getTypeMapping().isVoid());
    }

    public void updateHash(JrpcgenSHA hash) {
    	if (hasPayload()) {
    		if (isDefaultArm()) {
    			hash.update("default");
    		} else {
    			hash.update(value);
    		}
    		
    		element.updateHash(hash);
    	}
    }
    
    public void writeMemberDeclaration(JrpcgenJavaFile javaFile, String access, boolean initString) {
    	if (hasPayload()) {
        	element.writeMemberDeclaration(javaFile, access, initString);
    	}
    }
    
    public void startCase(JrpcgenJavaFile javaFile, String enclosure, JrpcgenContext context) {
    	if (isDefaultArm()) {
    		javaFile.elseBlock().println("default:");
    	} else {
    		javaFile.elseBlock().append("case ")
    			.append(JrpcgenConst.getAsCaseValue(value, enclosure, context))
    			.println(':');
    	}
    }
    
    public void endCase(JrpcgenJavaFile javaFile) {
    	if (! mapsToFollowingArm()) {
    		javaFile.beginLine().println("break;");
    	}
    }
    
    public void writeConstructorArm(JrpcgenJavaFile javaFile, String valueName, JrpcgenContext context) {
        //
        // Only emit code if arm does not map to another arm.
        //
        if (hasPayload()) {
            //
            // Arm does not contain void, so we need to spit out
            // encoding instructions.
            //
            javaFile.beginLine().append("this.").append(element.getIdentifier()).append(" = ");
            
            if (element.isArray()) {
            	javaFile.leftParenthesis().append(element.getTypeMapping().getJavaName()).append("[])")
            		.append(valueName);
            } else if (element.getTypeMapping().isStringType() || (! element.getTypeMapping().isBaseType())) {
            	javaFile.leftParenthesis().append(element.getTypeMapping().getJavaName()).rightParenthesis().append(valueName);
            } else if (element.getTypeMapping().isBooleanType()) {
            	javaFile.append("((Boolean)").append(valueName).append(").booleanValue()");
            } else {
            	/*
            	 * At this point numeric types are remaining, only.
            	 */
            	javaFile.append("((Number)").append(valueName).append(").").append(element.getTypeMapping().getJavaName()).append("Value()");
            }
            
            javaFile.println(';');
        }
    }
    
    public void writeEncodingPart(JrpcgenJavaFile javaFile, String enclosure, JrpcgenContext context) {
    	if (hasPayload()) {
    		element.writeEncodingPart(javaFile, enclosure, context);
    	}
    }
    
    public void writeDecodingPart(JrpcgenJavaFile javaFile, String enclosure, JrpcgenContext context) {
    	if (hasPayload()) {
    		element.writeDecodingPart(javaFile, enclosure, context);
    	}
    }
    
    public void writeToStringPart(JrpcgenJavaFile javaFile, JrpcgenContext context) {
    	if (hasPayload()) {
        	javaFile.beginLine().append("ret += ");
        	
            if(element.isArray()) {
            	javaFile.append("java.util.Arrays.toString(this.").append(element.getIdentifier());
            } else {
            	javaFile.append("this.").append(element.getIdentifier());
            }
            
        	javaFile.append(";").newLine();
    	}
    }
    
    public void writeEqualsPart(JrpcgenJavaFile javaFile, JrpcgenContext context) {
    	if (hasPayload()) {
        	javaFile.beginLine().append("ret = ");
        	element.writeEqualsExpression(javaFile, /* negate */ false, context);
        	javaFile.println(";");
    	}
    }
    
    @Override
    public String toString() {
    	String armAsString = "";
    	String armValue = (value != null ? value : "default");
    	
    	if (element == null){
    		armAsString = "  " + armValue + ": -";
    	} else if (element.getIdentifier() != null) {
    		armAsString = "  " + armValue + ": " + Objects.toString(element);
    	} else {
    		armAsString = "  " + armValue + ": void";
    	}
    	
    	return armAsString;
    }
    
    /**
     * Dumps the union arm to <code>System.out</code>.
     */
    public void dump() {
    	dump(System.out).println();
    }
    
    public <T extends Appendable> T dump(T appendable) {
    	try {
    		appendable.append(value != null ? value : "default");
    		
    		if (element == null) {
    			appendable.append(": -");
    		} else if (element.getIdentifier() != null) {
    			element.dump(appendable.append(": "));
    		} else {
    			appendable.append(": void");
    		}
    	} catch (IOException ioExcepion) {
    		// Ignored at this place.
    	}
    	
    	return appendable;
    }

}

// End of JrpcgenUnionArm.java