<commit_before>//
//  Cart.swift
//  moltin iOS
//
//  Created by <NAME> on 26/02/2018.
//

import Foundation

/// The meta information for a `Cart`
public class CartMeta: Codable {
    /// The display price information for this cart
    public let displayPrice: DisplayPrices

    enum CodingKeys: String, CodingKey {
        case displayPrice = "display_price"
    }
}

/// The display price for a `CartItem`
public struct CartItemDisplayPrice: Codable {
    /// The unit price for a cart item
    public let unit: DisplayPrice
    /// The value price (based on quantity) for a cart item
    public let value: DisplayPrice
}


open class CartItemPrice: Codable {
    /// The price for this cart item
    public var amount: Int
    /// The price for this cart item including tax
    public var includes_tax:  Bool?
    /// The type of this object
    
    enum CodingKeys: String, CodingKey {
        case amount = "amount"
        case includes_tax = "includes_tax"
    }
    
    /// Create a new address with first name and last name
    public init(
        amount: Int,
        includes_tax: Bool?) {
        self.amount = amount
        self.includes_tax = includes_tax
    }
    
    func toDictionary() -> [String: Any] {
        var data: [String: Any] = [:]
        
        data["amount"] = self.amount
        data["includes_tax"] = self.includes_tax
        return data
    }
}


/// The display prices information for a `CartItem`
public struct CartItemDisplayPrices: Codable {
    /// The display price for this cart item including tax
    public let withTax: CartItemDisplayPrice
    /// The display price for this cart item without tax
    public let withoutTax: CartItemDisplayPrice
    /// The display price for this cart item's tax amount
    public let tax: CartItemDisplayPrice

    enum CodingKeys: String, CodingKey {
        case withTax = "with_tax"
        case withoutTax = "without_tax"
        case tax
    }
}

/// The meta information for this `CartItem`
public class CartItemMeta: Codable {
    /// The display price for this cart item
    public let displayPrice: CartItemDisplayPrices

    enum CodingKeys: String, CodingKey {
        case displayPrice = "display_price"
    }
}

/// Represents a `Cart` in Moltin
open class Cart: Codable {
    /// The id for this cart
    public let id: String
    /// The type of this object
    public let type: String
    /// The external links for this cart
    public let links: [String: String]?
    /// The meta information for this cart
    public let meta: CartMeta?
}

/// Represents a `CartItem` in Moltin
open class CartItem: Codable {
    /// The id for this cart item
    public let id: String
    /// The type of this object
    public let type: String
    /// The product ID for this `CartItem`
    public let productId: String
    /// The name of this cart item
    public let name: String
    /// The description of this cart item
    public let description: String
    /// The SKU of this cart item
    public let sku: String
    /// The quantity of this cart item
    public let quantity: Int
    /// The price for this cart item
    public let unitPrice: ProductPrice
    /// The price for this cart item, taking into account quantity
    public let value: ProductPrice
    /// The tax for this cart item, taking into account quantity
    public var taxes: [TaxItem]?
    /// The external links for this cart item
    public let links: [String: String]
    /// The meta information for this cart item
    public let meta: CartItemMeta
    /// The relationships this item has
    public let relationships: Relationships?

    enum CodingKeys: String, CodingKey {
        case productId = "product_id"
        case unitPrice = "unit_price"

        case id
        case type
        case name
        case description
        case sku
        case quantity
        case value
        case links
        case meta
        case relationships
    }

    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let includes: IncludesContainer = decoder.userInfo[.includes] as? IncludesContainer ?? [:]

        self.id = try container.decode(String.self, forKey: .id)
        self.type = try container.decode(String.self, forKey: .type)
        self.productId = try container.decode(String.self, forKey: .productId)
        self.name = try container.decode(String.self, forKey: .name)
        self.description = try container.decode(String.self, forKey: .description)
        self.sku = try container.decode(String.self, forKey: .sku)
        self.quantity = try container.decode(Int.self, forKey: .quantity)
        self.unitPrice = try container.decode(ProductPrice.self, forKey: .unitPrice)
        self.value = try container.decode(ProductPrice.self, forKey: .value)
        self.links = try container.decode([String: String].self, forKey: .links)
        self.meta = try container.decode(CartItemMeta.self, forKey: .meta)
        self.relationships = try? container.decode(Relationships.self, forKey: .relationships)

        try self.decodeRelationships(fromRelationships: self.relationships, withIncludes: includes)
    }
}

extension CartItem {

    func decodeRelationships(
        fromRelationships relationships: Relationships?,
        withIncludes includes: IncludesContainer
        ) throws {

        self.taxes = try self.decodeMany(
            fromRelationships: relationships?[keyPath: \Relationships.taxes],
            withIncludes: includes["tax_items"])

    }
}

/// Represents various types of cart items
public enum CartItemType: String {
    /// A standard cart item
    case cartItem = "cart_item"
    /// A promo item
    case promotionItem = "promotion_item"
}

/// A custom cart item
open class CustomCartItem: Codable {
    var name: String
    var sku: String?
    var quantity: Int
    var description: String?
    var price: CartItemPrice
    var attributes: [String: String]?

    public init(withName name: String, sku: String?, quantity: Int, description: String?, price: CartItemPrice, withAttributes attributes: [String: String]? = nil) {
        self.name = name
        self.sku = sku
        self.quantity = quantity
        self.description = description
        self.price = price
        
        self.attributes = attributes
    }
    
    func toDictionary() -> [String: Any] {
        var cartItemData: [String: Any] = [:]
        if let sku = self.sku {
            cartItemData["sku"] = sku
        }
        if let description = self.description {
            cartItemData["description"] = description
        }
        cartItemData["name"] = self.name
        cartItemData["quantity"] = self.quantity
        cartItemData["price"] = self.price.toDictionary()

        if let attributes = self.attributes {
            cartItemData = attributes
        }
        
        return cartItemData
    }
    
}

/// A tax item
open class TaxItem: Codable {

    public let type: String
    public let id: String
    public let jurisdiction: String
    public let code: String
    public let name: String
    public let rate: Float
}
<commit_msg>Make sure the cart object can handle the custom cart optionals.<commit_after>//
//  Cart.swift
//  moltin iOS
//
//  Created by <NAME> on 26/02/2018.
//

import Foundation

/// The meta information for a `Cart`
public class CartMeta: Codable {
    /// The display price information for this cart
    public let displayPrice: DisplayPrices

    enum CodingKeys: String, CodingKey {
        case displayPrice = "display_price"
    }
}

/// The display price for a `CartItem`
public struct CartItemDisplayPrice: Codable {
    /// The unit price for a cart item
    public let unit: DisplayPrice
    /// The value price (based on quantity) for a cart item
    public let value: DisplayPrice
}


open class CartItemPrice: Codable {
    /// The price for this cart item
    public var amount: Int
    /// The price for this cart item including tax
    public var includes_tax:  Bool?
    /// The type of this object
    
    enum CodingKeys: String, CodingKey {
        case amount = "amount"
        case includes_tax = "includes_tax"
    }
    
    /// Create a new address with first name and last name
    public init(
        amount: Int,
        includes_tax: Bool?) {
        self.amount = amount
        self.includes_tax = includes_tax
    }
    
    func toDictionary() -> [String: Any] {
        var data: [String: Any] = [:]
        
        data["amount"] = self.amount
        data["includes_tax"] = self.includes_tax
        return data
    }
}


/// The display prices information for a `CartItem`
public struct CartItemDisplayPrices: Codable {
    /// The display price for this cart item including tax
    public let withTax: CartItemDisplayPrice
    /// The display price for this cart item without tax
    public let withoutTax: CartItemDisplayPrice
    /// The display price for this cart item's tax amount
    public let tax: CartItemDisplayPrice

    enum CodingKeys: String, CodingKey {
        case withTax = "with_tax"
        case withoutTax = "without_tax"
        case tax
    }
}

/// The meta information for this `CartItem`
public class CartItemMeta: Codable {
    /// The display price for this cart item
    public let displayPrice: CartItemDisplayPrices

    enum CodingKeys: String, CodingKey {
        case displayPrice = "display_price"
    }
}

/// Represents a `Cart` in Moltin
open class Cart: Codable {
    /// The id for this cart
    public let id: String
    /// The type of this object
    public let type: String
    /// The external links for this cart
    public let links: [String: String]?
    /// The meta information for this cart
    public let meta: CartMeta?
}

/// Represents a `CartItem` in Moltin
open class CartItem: Codable {
    /// The id for this cart item
    public let id: String
    /// The type of this object
    public let type: String
    /// The product ID for this `CartItem`
    public let productId: String?
    /// The name of this cart item
    public let name: String
    /// The description of this cart item
    public let description: String?
    /// The SKU of this cart item
    public let sku: String?
    /// The quantity of this cart item
    public let quantity: Int
    /// The price for this cart item
    public let unitPrice: ProductPrice
    /// The price for this cart item, taking into account quantity
    public let value: ProductPrice
    /// The tax for this cart item, taking into account quantity
    public var taxes: [TaxItem]?
    /// The external links for this cart item
    public let links: [String: String]
    /// The meta information for this cart item
    public let meta: CartItemMeta
    /// The relationships this item has
    public let relationships: Relationships?

    enum CodingKeys: String, CodingKey {
        case productId = "product_id"
        case unitPrice = "unit_price"

        case id
        case type
        case name
        case description
        case sku
        case quantity
        case value
        case links
        case meta
        case relationships
    }

    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let includes: IncludesContainer = decoder.userInfo[.includes] as? IncludesContainer ?? [:]

        self.id = try container.decode(String.self, forKey: .id)
        self.type = try container.decode(String.self, forKey: .type)
        self.productId = try? container.decode(String.self, forKey: .productId)
        self.name = try container.decode(String.self, forKey: .name)
        self.description = try container.decode(String.self, forKey: .description)
        self.sku = try container.decode(String.self, forKey: .sku)
        self.quantity = try container.decode(Int.self, forKey: .quantity)
        self.unitPrice = try container.decode(ProductPrice.self, forKey: .unitPrice)
        self.value = try container.decode(ProductPrice.self, forKey: .value)
        self.links = try container.decode([String: String].self, forKey: .links)
        self.meta = try container.decode(CartItemMeta.self, forKey: .meta)
        self.relationships = try? container.decode(Relationships.self, forKey: .relationships)

        try self.decodeRelationships(fromRelationships: self.relationships, withIncludes: includes)
    }
}

extension CartItem {

    func decodeRelationships(
        fromRelationships relationships: Relationships?,
        withIncludes includes: IncludesContainer
        ) throws {

        self.taxes = try self.decodeMany(
            fromRelationships: relationships?[keyPath: \Relationships.taxes],
            withIncludes: includes["tax_items"])

    }
}

/// Represents various types of cart items
public enum CartItemType: String {
    /// A standard cart item
    case cartItem = "cart_item"
    /// A promo item
    case promotionItem = "promotion_item"
}

/// A custom cart item
open class CustomCartItem: Codable {
    var name: String
    var sku: String?
    var quantity: Int
    var description: String?
    var price: CartItemPrice
    var attributes: [String: String]?

    public init(withName name: String, sku: String?, quantity: Int, description: String?, price: CartItemPrice, withAttributes attributes: [String: String]? = nil) {
        self.name = name
        self.sku = sku
        self.quantity = quantity
        self.description = description
        self.price = price
        
        self.attributes = attributes
    }
    
    func toDictionary() -> [String: Any] {
        var cartItemData: [String: Any] = [:]
        if let sku = self.sku {
            cartItemData["sku"] = sku
        }
        if let description = self.description {
            cartItemData["description"] = description
        }
        cartItemData["name"] = self.name
        cartItemData["quantity"] = self.quantity
        cartItemData["price"] = self.price.toDictionary()

        if let attributes = self.attributes {
            cartItemData = attributes
        }
        
        return cartItemData
    }
    
}

/// A tax item
open class TaxItem: Codable {

    public let type: String
    public let id: String
    public let jurisdiction: String
    public let code: String
    public let name: String
    public let rate: Float
}

{'fraction_non_alphanumeric': 0.08387860225532508, 'fraction_numerical': 0.0011137407768341918, 'mean_word_length': 2.4354375896700144, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, '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': '3718123', 'n_tokens_mistral': 3960, 'n_tokens_neox': 3835, 'n_words': 1432}