/***************************************************************************
 *   Copyright (C) 2011 by Fabrizio Montesi <famontesi@gmail.com>          *
 *                                                                         *
 *   This program 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 program 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 Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   For details about the authors of this software, see the AUTHORS file. *
 ***************************************************************************/

package jolie.net.http.json;

import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import java.util.Map.Entry;
import jolie.runtime.Value;
import jolie.runtime.ValueVector;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;

/**
 *
 * @author Fabrizio Montesi
 */
public class JsonUtils
{
	private final static String ROOT_SIGN = "$";

	public static void valueToJsonString( Value value, StringBuilder builder )
		throws IOException
	{
		if ( value.children().isEmpty() ) {
			if ( value.isDefined() ) {
				builder.append( nativeValueToJsonString( value ) );
			}
		} else {
			builder.append( '{' );
			if ( value.isDefined() ) {
				appendKeyColon( builder, ROOT_SIGN );
				builder.append( nativeValueToJsonString( value ) );
			}
			int size = value.children().size();
			int i = 0;
			for( Entry< String, ValueVector > child : value.children().entrySet() ) {
				if ( child.getValue().isEmpty() == false ) {
					appendKeyColon( builder, child.getKey() );
					valueVectorToJsonString( child.getValue(), builder );
				}
				if ( i++ < size - 1 ) {
					builder.append( ',' );
				}
			}
			builder.append( '}' );
		}	
		
	}

	private static void valueVectorToJsonString( ValueVector vector, StringBuilder builder )
		throws IOException
	{
		if ( vector.size() > 1 ) {
			builder.append( '[' );
			for( int i = 0; i < vector.size(); i++ ) {
				valueToJsonString( vector.get( i ), builder );
				if ( i < vector.size() - 1 ) {
					builder.append( ',' );
				}
			}
			builder.append( ']' );
		} else {
			valueToJsonString( vector.first(), builder );
		}
	}

	private static void appendKeyColon( StringBuilder builder, String key )
	{
		builder.append( '"' )
			.append( key )
			.append( "\":" );
	}

	private static String nativeValueToJsonString( Value value )
		throws IOException
	{
		if ( value.isInt() || value.isDouble() ) {
			return value.strValue();
		} else {
			return '"' + JSONValue.escape( value.strValue() ) + '"';
		}
	}

	public static void parseJsonIntoValue( Reader reader, Value value )
		throws IOException
	{
		try {
			jsonObjectToValue( (JSONObject)JSONValue.parseWithException( reader ), value );
		} catch( ParseException e ) {
			throw new IOException( e );
		} catch( ClassCastException e ) {
			throw new IOException( e );
		}
	}

	private static void jsonObjectToValue( JSONObject obj, Value value )
	{
		Map< String, Object > map = (Map< String, Object >)obj;
		ValueVector vec;
		for( Entry< String, Object > entry : map.entrySet() ) {
			if ( entry.getKey().equals( ROOT_SIGN ) ) {
				if ( entry.getValue() instanceof String ) {
					value.setValue( (String) entry.getValue() );
				} else if ( entry.getValue() instanceof Double ) {
					value.setValue( (Double)entry.getValue() );
				} else if ( entry.getValue() instanceof Integer ) {
					value.setValue( (Integer)entry.getValue() );
				} else if ( entry.getValue() instanceof Long ) {
					value.setValue( ((Long)entry.getValue()).intValue() );
				} else if ( entry.getValue() instanceof Boolean ){
					Boolean b = (Boolean)entry.getValue();
					if ( b ) {
						value.setValue( 1 );
					} else {
						value.setValue( 0 );
					}
				} else {
					value.setValue( entry.getValue().toString() );
				}
			} else {
				vec = jsonObjectToValueVector( entry.getValue() );
				value.children().put( entry.getKey(), vec );
			}
		}
	}

	private static ValueVector jsonObjectToValueVector( Object obj )
	{
		ValueVector vec = ValueVector.create();
		if ( obj instanceof JSONObject ) {
			Value val = Value.create();
			jsonObjectToValue( (JSONObject)obj, val );
			vec.add( val );
		} else if ( obj instanceof JSONArray ) {
			JSONArray array = (JSONArray) obj;
			for ( Object element : array ) {
				if ( element instanceof JSONObject ) {
					Value val = Value.create();
					jsonObjectToValue( (JSONObject)element, val );
					vec.add( val );
				} else {
					vec.add( getBasicValue( element ) );
				}
			}
		} else {
			vec.add( getBasicValue( obj ) );
		}
		return vec;
	}
	
	private static Value getBasicValue( Object obj )
	{
		Value val = Value.create();
		if ( obj instanceof String ) {
			val.setValue( (String) obj );
		} else if ( obj instanceof Double ) {
			val.setValue( (Double) obj );
		} else if ( obj instanceof Integer ) {
			val.setValue( (Integer) obj );
		} else if ( obj instanceof Long ) {
			val.setValue( ((Long) obj).intValue() );
		} else if ( obj instanceof Boolean ) {
			Boolean b = (Boolean) obj;
			if ( b ) {
				val.setValue( 1 );
			} else {
				val.setValue( 0 );
			}
		} else if ( obj == null ) {
                        
                } else {
			val.setValue( obj.toString() );
		}
		return val;
	}
}

@@ -6215,16 +6215,45 @@
         
+val.setValue( new String() );
 %0A       

modify JSON null field conversion: from void to empty string