/* ************************************************************************
#
#  DivConq
#
#  http://divconq.com/
#
#  Copyright:
#    Copyright 2012 eTimeline, LLC. All rights reserved.
#
#  License:
#    See the license.txt file in the project's top-level directory for details.
#
#  Authors:
#    * Andy White
#
************************************************************************ */
package divconq.struct;

import divconq.lang.Memory;
import divconq.lang.OperationResult;
import divconq.schema.DataType;
import divconq.struct.builder.BuilderStateException;
import divconq.struct.builder.ICompositeOutput;
import divconq.struct.builder.MemoryBuilder;

/**
 * DivConq uses a specialized type system that provides type consistency across services 
 * (including web services), database fields and stored procedures, as well as scripting.
 * 
 * All scalars (including primitives) and composites (collections) are wrapped by some
 * subclass of Struct.  All composites are wrapped by a subclass of this class.  See
 * ListStruct and RecordStruct.
 * 
 *  TODO link to blog entries.
 * 
 * @author Andy
 *
 */
abstract public class CompositeStruct extends Struct implements ICompositeOutput {
	public CompositeStruct() {
	}
	
	public CompositeStruct(DataType type) {
		super(type);
	}
	
	/**
	 * A way to select a child or sub child structure similar to XPath but lightweight.
	 * Can select composites and scalars.  Use a . or / delimiter.
	 * 
	 * For example: "Toys.3.Name" called on "Person" Record means return the (Struct) name of the 
	 * 4th toy in this person's Toys list.
	 * 
	 * Cannot go up levels, or back to root.  Do not start with a dot or slash as in ".People".
	 * 
	 * @param log collect messages about this call
	 * @param path string holding the path to select
	 * @return selected structure if any, otherwise null
	 */
	public Struct select(OperationResult log, String path) {
		return this.select(PathPart.parse(log, path));
	} 
	
	/**
	 * A way to select a child or sub child structure similar to XPath but lightweight.
	 * Can select composites and scalars.  Use a . or / delimiter.
	 * 
	 * For example: "Toys.3.Name" called on "Person" Record means return the (Struct) name of the 
	 * 4th toy in this person's Toys list.
	 * 
	 * Cannot go up levels, or back to root.  Do not start with a dot or slash as in ".People".
	 * 
	 * @param path parts of the path holding a list index or a field name
	 * @return selected structure if any, otherwise null
	 */
	abstract public Struct select(PathPart... path);	
	
	/**
	 * Does this collection have any items or fields
	 * 
	 * @return true if no items or fields
	 */
	abstract public boolean isEmpty();
	
	/**
	 * Remove all child fields or items.
	 */
	abstract public void clear();
	
	@Override
	public String toString() {
		try {
			MemoryBuilder rb = new MemoryBuilder();		
			this.toBuilder(rb);		
			return rb.toString();
		}
		catch (Exception x) {
			//
		}
		
		return null;
	}
	
	/**
	 * Convert the structure to Json and return in Memory (think StringBuilder in this usage).
	 *  
	 * @return Memory holding JSON representation of this structure and all children
	 * @throws BuilderStateException if the structure is invalid then this exception arises
	 */
	public Memory toMemory() throws BuilderStateException {
		MemoryBuilder rb = new MemoryBuilder();		
		this.toBuilder(rb);		
		return rb;
	}
}
