<commit_before>//
//  Mapper.swift
//  ObjectMapper
//
//  Created by <NAME> on 2014-10-09.
//  Copyright (c) 2014 hearst. All rights reserved.
//

import Foundation

public protocol Mappable {
	mutating func map(map: Map)
	init()
}

enum MappingType {
	case fromJSON
	case toJSON
}

/**
* A class used for holding mapping data
*/
public class Map {
	var JSONDictionary: [String : AnyObject] = [:]
	var currentValue: AnyObject?
	var currentKey: String?
	var mappingType: MappingType = .fromJSON

	public init(){
		
	}
	
	/**
	* Sets the current mapper value and key
	*/
	public subscript(key: String) -> Map {
		// save key and value associated to it
		currentKey = key
		currentValue = valueFor(key)
		
		return self
	}
	
	/**
	* Fetch value from JSON dictionary
	*/
	private func valueFor<N>(key: String) -> N? {
		// key can the form "distance.value", to allow mapping to sub objects
		
		// break down the components of the key and loop through them until we reach the desired object
		let components = key.componentsSeparatedByString(".")
		var index = 0
		var temp = JSONDictionary
		while index < components.count {
			let currentKey = components[index]
			if index == components.count - 1 {
				return temp[currentKey] as? N
			} else {
				if temp[currentKey] is NSNull {
					return nil
				}
				if let dict = temp[currentKey] as [String : AnyObject]? {
					temp = dict
					index++
				} else {
					return nil
				}
			}
		}
		
		return (JSONDictionary[key] as? N)
	}
}

public class Mapper<N: Mappable> {
	var map = Map()
	
	public init(){

	}
	
	// MARK: Public Mapping functions
	
	/**
	 * Map a JSON string onto an existing object
	 */
	public func map(string JSONString: String, var toObject object: N) -> N! {
		if let JSON = parseJSONDictionary(JSONString) {
			return map(JSON, toObject: object)
		}
		return nil
	}

	/**
	* Map a JSON string to an object that conforms to Mappable
	*/
	public func map(string JSONString: String) -> N! {
		if let JSON = parseJSONDictionary(JSONString) {
			return map(JSON)
		}
		return nil
	}

	/**
	* Maps a JSON dictionary to an object that conforms to Mappable
	*/
	public func map(JSON: [String : AnyObject]) -> N! {
		let object = N()
		return map(JSON, toObject: object)
	}

	/**
	* Maps a JSON dictionary to an existing object that conforms to Mappable.
	* Usefull for those pesky objects that have crappy designated initializers like NSManagedObject
	*/
	public func map(JSON: [String : AnyObject], var toObject object: N) -> N! {
		map.mappingType = .fromJSON
		map.JSONDictionary = JSON
		object.map(map)
		return object
	}

	/**
	* Maps a JSON array to an object that conforms to Mappable
	*/
	public func mapArray(string JSONString: String) -> [N] {
		if let JSONArray = parseJSONArray(JSONString) {
			return mapArray(JSONArray)
		}

		// failed to parse JSON into array form
		// try to parse it into a dictionary and then wrap it in an array
		if let JSONDict = parseJSONDictionary(JSONString) {
			return mapArray([JSONDict])
		}

		return []
	}
	
	/**
	* Maps a JSON dictionary to an array of object that conforms to Mappable
	*/
	public func mapArray(JSON: [[String : AnyObject]]) -> [N] {
		return JSON.map {
			self.map($0)
		}		
	}

	// MARK: public toJSON functions
	
	/**
	* Maps an object that conforms to Mappable to a JSON dictionary <String : AnyObject>
	*/
	public func toJSON(var object: N) -> [String : AnyObject] {
		map.mappingType = .toJSON
		map.JSONDictionary = [String : AnyObject]()
		
		object.map(map)

		return map.JSONDictionary
	}
	
	/** 
	* Maps an array of Objects to an array of JSON dictionaries [[String : AnyObject]]
	*/
	public func toJSONArray(array: [N]) -> [[String : AnyObject]] {
		return array.map {
			self.toJSON($0)
		}
	}

	/** 
	* Maps an Object to a JSON string
	*/
	public func toJSONString(object: N, prettyPrint: Bool) -> String! {
		let JSONDict = toJSON(object)

		var err: NSError?<commit_msg>Make Mapper and Map more immutable<commit_after>//
//  Mapper.swift
//  ObjectMapper
//
//  Created by <NAME> on 2014-10-09.
//  Copyright (c) 2014 hearst. All rights reserved.
//

import Foundation

public protocol Mappable {
	mutating func map(map: Map)
	init()
}

enum MappingType {
	case fromJSON
	case toJSON
}

/**
* A class used for holding mapping data
*/
public class Map {
	let mappingType: MappingType

	var JSONDictionary: [String : AnyObject] = [:]
	var currentValue: AnyObject?
	var currentKey: String?

	private init(mappingType: MappingType, JSONDictionary: [String : AnyObject]) {
		self.mappingType = mappingType
		self.JSONDictionary = JSONDictionary
	}
	
	/**
	* Sets the current mapper value and key
	*/
	public subscript(key: String) -> Map {
		// save key and value associated to it
		currentKey = key
		currentValue = valueFor(key)
		
		return self
	}
	
	/**
	* Fetch value from JSON dictionary
	*/
	private func valueFor<N>(key: String) -> N? {
		// key can the form "distance.value", to allow mapping to sub objects
		
		// break down the components of the key and loop through them until we reach the desired object
		let components = key.componentsSeparatedByString(".")
		var index = 0
		var temp = JSONDictionary
		while index < components.count {
			let currentKey = components[index]
			if index == components.count - 1 {
				return temp[currentKey] as? N
			} else {
				if temp[currentKey] is NSNull {
					return nil
				}
				if let dict = temp[currentKey] as [String : AnyObject]? {
					temp = dict
					index++
				} else {
					return nil
				}
			}
		}
		
		return (JSONDictionary[key] as? N)
	}
}

public class Mapper<N: Mappable> {
	public init(){

	}
	
	// MARK: Public Mapping functions
	
	/**
	 * Map a JSON string onto an existing object
	 */
	public func map(string JSONString: String, var toObject object: N) -> N! {
		if let JSON = parseJSONDictionary(JSONString) {
			return map(JSON, toObject: object)
		}
		return nil
	}

	/**
	* Map a JSON string to an object that conforms to Mappable
	*/
	public func map(string JSONString: String) -> N! {
		if let JSON = parseJSONDictionary(JSONString) {
			return map(JSON)
		}
		return nil
	}

	/**
	* Maps a JSON dictionary to an object that conforms to Mappable
	*/
	public func map(JSON: [String : AnyObject]) -> N! {
		let object = N()
		return map(JSON, toObject: object)
	}

	/**
	* Maps a JSON dictionary to an existing object that conforms to Mappable.
	* Usefull for those pesky objects that have crappy designated initializers like NSManagedObject
	*/
	public func map(JSON: [String : AnyObject], var toObject object: N) -> N! {
		let map = Map(mappingType: .fromJSON, JSONDictionary: JSON)
		object.map(map)
		return object
	}

	/**
	* Maps a JSON array to an object that conforms to Mappable
	*/
	public func mapArray(string JSONString: String) -> [N] {
		if let JSONArray = parseJSONArray(JSONString) {
			return mapArray(JSONArray)
		}

		// failed to parse JSON into array form
		// try to parse it into a dictionary and then wrap it in an array
		if let JSONDict = parseJSONDictionary(JSONString) {
			return mapArray([JSONDict])
		}

		return []
	}
	
	/**
	* Maps a JSON dictionary to an array of object that conforms to Mappable
	*/
	public func mapArray(JSON: [[String : AnyObject]]) -> [N] {
		return JSON.map {
			self.map($0)
		}		
	}

	// MARK: public toJSON functions
	
	/**
	* Maps an object that conforms to Mappable to a JSON dictionary <String : AnyObject>
	*/
	public func toJSON(var object: N) -> [String : AnyObject] {
		let map = Map(mappingType: .toJSON, JSONDictionary: [:])
		object.map(map)
		return map.JSONDictionary
	}
	
	/** 
	* Maps an array of Objects to an array of JSON dictionaries [[String : AnyObject]]
	*/
	public func toJSONArray(array: [N]) -> [[String : AnyObject]] {
		return array.map {
			self.toJSON($0)
		}
	}

	/** 
	* Maps an Object to a JSON string
	*/
	public func toJSONString(object: N, prettyPrint: Bool) -> String! {
		let JSONDict = toJSON(object)

		var err: NSError?
{'fraction_non_alphanumeric': 0.10688656678836711, 'fraction_numerical': 0.004028704519702883, 'mean_word_length': 3.103305785123967, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2736877', 'n_tokens_mistral': 2837, 'n_tokens_neox': 2503, 'n_words': 898}