//
//  MCMLBuilder.h
//  MCHTTPServer
//
//  Created by Alykhan Jetha on 09-09-10.
//  Copyright 2009 Marketcircle, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>


@class MCHTMLBuilder;
@class MCXMLBuilder;

typedef enum _MCMLDocType {
	MCHTML401StrictDocType			= 10,
	MCHTML401TransitionalDocType	= 20,
	MCXHTML10FramesetDocType		= 30,
	MCXHTML10StrictDocType			= 40,
	MCXHTML10TransitionalDocType	= 50,
	MCXHTML11DocType				= 60,
	MCHTML5DocType					= 70
} MCMLDocType;

typedef enum _MCMLMode {
	MCMLBasicMode					= 0,
	MCMLTemplateMode				= 10
}MCMLMode;

extern NSString *MLHeads;
extern NSString *MLData;

/*!
 Builds up an XML or HTML (depending on the subclass) document easily. Made to be used by FScript, but as easily used by Objc.
 
 To make things easily in building output, you can use FScript blocks. To interate over arrays use do:.
 Since the below example is in FScript, you can easily tweak without needing a compile (handly when dealing with HTML, CSS, Javacript.
 Better yet, you have full flow control. You don't have do convoluted stuff in a file template.
 
 
 Special subclass considerations:
 MCXMLBuilder is strick because it uses NSXML stuff underneat, but it also gives you additional functionality such as options to get the string with single quotes vs. double quotes etc... by getting the xmldoc and messaging it directly. The downside is that you can't set the doctype on MCXMLBuilder (not sure why).
 MCHTMLBuilder implements the same API but uses a string buffer underneat.
 
 
 addressBlock := [:o |
 	o completeAddressString stringByReplacingOccurrencesOfString:'\n' withString:'<br />'.].
 
 
 b := MCMLBuilder HTMLBuilder.
 b add:'body'.
 	b add:'table' a:#{'cellpadding'->2, 'cellspacing'->2, 'border'->1}.
 	contacts do:[:e |
 		b add:'tr'.
 			b add:'td'.
 				b add:'h1' v:([:o | o name] value:e) p:true.
 				b add:'p'.
 					b addText:(addressBlock value:(e defaultGeoAddress)).
 				b pop.
 			b pop.
 			b add:'td'.
 				b add:'p'.
 					b add:'a' a:#{'href'->([:o :base | base ++ '?id='++ (o contactID stringValue)] value:e value:'/db/scripts/contact'), 'target'->'_blank'} v:'Go here' p:true.
 				b pop.
 			b pop.
 		b pop.
 	].
 	b pop.
 b pop.
 
 stringOutput := b stringRepresentation.
 dataOutput := b dataRepresentation.
 
 
 */
@interface MCMLBuilder : NSObject {
	NSURL *templatePath;
	NSString *templateAsString;
	NSMutableDictionary *templateData;
	MCMLMode mode;
	
}

+ (MCHTMLBuilder *)HTMLBuilder;
+ (MCXMLBuilder *)XMLBuilder;

/*!
 Sets the doc type on the document at the top. Note that XMLBuilder does not implement this because I couldn't figure out how to put the proper doctype in.
 */
- (void)setDocType:(MCMLDocType)aType;

- (void)setHTML401StrictDocType;
- (void)setHTML401TransitionalDocType;
- (void)setXHTML10FramesetDocType;
- (void)setXHTML10StrictDocType;
- (void)setXHTML10TransitionalDocType;
- (void)setXHTML11DocType;
- (void)setHTM5DocType;



- (MCMLMode)mode;

/*!
 Reserved words: MLHeads, MLData, MLFrameworkResourcePath, MLBundleResourcePath
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
 <html>
 	<head>
		<link rel="stylesheet" href="{{MLFrameworkResourcePath}}/demo.css" type="text/css" media="screen">
 		<link rel="stylesheet" href="{{MLBundleResourcePath}}/my.css" type="text/css" media="screen">

 		{{foreach headitem MCHeads do}}
 		{{headitem}}
 		{{endforeach do}}
 	</head>
 	<body>
 		{{MLData}}
 	</body>
 </html>
 
 
 [myMLBuilder addTemplateData:@"<script src=\"http://widgets.twimg.com/j/2/widget.js\"></script>" forArrayKey:@"MLHeads"];
 
 */
- (id)initWithTemplateAtPath:(NSURL *)aPath;
- (id)initWithTemplateString:(NSString *)aString;

- (NSMutableDictionary *)templateData;
- (void)setTemplateData:(id)obj forKey:(NSString *)aKey;
- (void)addTemplateData:(id)obj forArrayKey:(NSString *)aKey;

/*!
 Convenience that calls addTemplateData: forArrayKey:@"MLHeads"
 */
- (void)addTemplateHeadsString:(NSString *)aHeads;



/*!
 */
- (id)take:(MCMLBuilder *)builder pop:(BOOL)pop;

/*!
 Replace occurances of <, >, ", and ' in string with HTML character entity
 */
- (NSString *)sanitizedStringFrom:(NSString *)dirtyString;

/*!
 "name" is the name of the node (i.e. body, div, table etc...).
 "attribs" is a dictionary of attributes of the node (i.e href = "someURL", target = "_blank" etc...). XMLBuilder requires a dictionary, but HTMLBuilder can take either a dictionary or a string. In ObjC, you can use single quotes in the string - HTMLBuilder will auto replace single quotes with double quotes.
 
 "block" is an object that responds to "value" (FSBlock evaluates with that call). value should return a foundation basic type such as NSString, NSNumber, NSDate, NSURL, NSData. Alternatively, block can be one of those foundation types as well.
 "pop" dictates whether the created XMLNode is made to the current node or just added as a child of the current node on the stack
 */
- (id)add:(NSString *)name a:(id)attribs v:(id)block p:(BOOL)pop;
- (id)add:(NSString *)name a:(id)attribs v:(id)block;
- (id)add:(NSString *)name a:(id)attribs;
- (id)add:(NSString *)name;

- (id)add:(NSString *)name v:(id)block p:(BOOL)pop;
- (id)add:(NSString *)name v:(id)block;

- (id)add:(NSString *)name a:(id)attribs p:(BOOL)pop;

- (id)add:(NSString *)name p:(BOOL)pop;

/*!
 Add text inside a 'p'. Special case to get around a bug in the xml(html) generation.
 */
- (id)addText:(id)block;
- (id)addSafeText:(id)block;

/*!
 Add comment inside a 'script' or 'style' for example.
 */
- (id)addComment:(id)block;


/*
 Essentially closes the current <node>. Pops the current node off the stack so to speak.
 */
- (void)pop;

/*!
 Subclassers must implement this
 */
- (NSString *)preliminaryStringRepresentation;

/*!
 If in template mode, calls preliminaryStringRepresentation and then merges the results into the template at MLData.
 */
- (NSString *)stringRepresentation;

/*!
 Returns stringRepresentation as a bag of UTF8 bytes
 */
- (NSData *)dataRepresentation;


@end
