     func toDic() -> [String: Any]
 }
 
+// MARK:- Weight Builder
 
 public class WeightBuilder: ScoreFunctionBuilder {
     
-    var weight: Decimal?
-    
-    typealias BuilderClosure = (WeightBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _weight: Decimal?
+    
+    public init() {}
+    
+    public func set(weight: Decimal) -> WeightBuilder {
+        self._weight = weight
+        return self
+    }
+    
+    public var weight: Decimal? {
+        return self._weight
     }
     
     public func build() throws -> WeightScoreFunction {
-        return WeightScoreFunction(withBuilder: self)
-    }
-    
-}
+        return try WeightScoreFunction(withBuilder: self)
+    }
+    
+}
+
+// MARK:- Randon Score Function Builder
 
 public class RandomScoreFunctionBuilder: ScoreFunctionBuilder {
     
-    var seed: Int?
-    var field: String?
-    
-    typealias BuilderClosure = (RandomScoreFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    public var _seed: Int?
+    public var _field: String?
+    
+    public init() {}
+    
+    public func set(seed: Int) -> RandomScoreFunctionBuilder {
+        self._seed = seed
+        return self
+    }
+    
+    public func set(field: String) -> RandomScoreFunctionBuilder {
+        self._field = field
+        return self
+    }
+    
+    public var seed: Int? {
+        return self._seed
+    }
+    public var field: String? {
+        return self._field
     }
     
     public func build() throws -> RandomScoreFunction {
-        return RandomScoreFunction(withBuilder: self)
-    }
-}
+        return try RandomScoreFunction(withBuilder: self)
+    }
+}
+
+// MARK:- ScriptScoreFunction Builder
 
 public class ScriptScoreFunctionBuilder: ScoreFunctionBuilder {
     
-    var script: Script?
-    
-    typealias BuilderClosure = (ScriptScoreFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _script: Script?
+    
+    public init() {}
+    
+    public func set(script: Script) -> ScriptScoreFunctionBuilder {
+        self._script = script
+        return self
+    }
+    
+    public var script: Script? {
+        return self._script
     }
     
     public func build() throws -> ScriptScoreFunction {
-        return ScriptScoreFunction(withBuilder: self)
-    }
-}
+        return try ScriptScoreFunction(withBuilder: self)
+    }
+}
+
+// MARK:- Linear Decay Function Builder
 
 public class LinearDecayFunctionBuilder: ScoreFunctionBuilder {
     
-    public var field: String?
-    public var origin: String?
-    public var scale: String?
-    public var offset: String?
-    public var decay: Decimal?
-    public var isMultiValue: Bool = false
-    public var multiValueMode: DecayScoreFunction.MultiValueMode = .MIN
-    
-    typealias BuilderClosure = (LinearDecayFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _field: String?
+    private var _origin: String?
+    private var _scale: String?
+    private var _offset: String?
+    private var _decay: Decimal?
+    private var _multiValueMode: MultiValueMode?
+    
+    public init() {}
+    
+    public func set(field: String) -> LinearDecayFunctionBuilder {
+        self._field = field
+        return self
+    }
+    public func set(origin: String) -> LinearDecayFunctionBuilder {
+        self._origin = origin
+        return self
+    }
+    public func set(scale: String) -> LinearDecayFunctionBuilder {
+        self._scale = scale
+        return self
+    }
+    public func set(offset: String) -> LinearDecayFunctionBuilder {
+        self._offset = offset
+        return self
+    }
+    public func set(decay: Decimal) -> LinearDecayFunctionBuilder {
+        self._decay = decay
+        return self
+    }
+    public func set(multiValudMode: MultiValueMode) -> LinearDecayFunctionBuilder {
+        self._multiValueMode = multiValudMode
+        return self
+    }
+    
+    public var field: String? {
+        return self._field
+    }
+    public var origin: String? {
+        return self._origin
+    }
+    public var scale: String? {
+        return self._scale
+    }
+    public var offset: String? {
+        return self._offset
+    }
+    public var decay: Decimal? {
+        return self._decay
+    }
+    public var multiValueMode: MultiValueMode? {
+        return self._multiValueMode
     }
     
     public func build() throws -> LinearDecayScoreFunction {
-        return LinearDecayScoreFunction(withBuilder: self)
-    }
-}
+        return try LinearDecayScoreFunction(withBuilder: self)
+    }
+}
+
+// MARK:- Gauss Decay Function Builder
 
 public class GaussDecayFunctionBuilder: ScoreFunctionBuilder {
     
-    public var field: String?
-    public var origin: String?
-    public var scale: String?
-    public var offset: String?
-    public var decay: Decimal?
-    public var isMultiValue: Bool = false
-    public var multiValueMode: DecayScoreFunction.MultiValueMode = .MIN
-    
-    typealias BuilderClosure = (GaussDecayFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _field: String?
+    private var _origin: String?
+    private var _scale: String?
+    private var _offset: String?
+    private var _decay: Decimal?
+    private var _multiValueMode: MultiValueMode?
+    
+    public init() {}
+    
+    public func set(field: String) -> GaussDecayFunctionBuilder {
+        self._field = field
+        return self
+    }
+    public func set(origin: String) -> GaussDecayFunctionBuilder {
+        self._origin = origin
+        return self
+    }
+    public func set(scale: String) -> GaussDecayFunctionBuilder {
+        self._scale = scale
+        return self
+    }
+    public func set(offset: String) -> GaussDecayFunctionBuilder {
+        self._offset = offset
+        return self
+    }
+    public func set(decay: Decimal) -> GaussDecayFunctionBuilder {
+        self._decay = decay
+        return self
+    }
+    public func set(multiValudMode: MultiValueMode) -> GaussDecayFunctionBuilder {
+        self._multiValueMode = multiValudMode
+        return self
+    }
+    
+    public var field: String? {
+        return self._field
+    }
+    public var origin: String? {
+        return self._origin
+    }
+    public var scale: String? {
+        return self._scale
+    }
+    public var offset: String? {
+        return self._offset
+    }
+    public var decay: Decimal? {
+        return self._decay
+    }
+    public var multiValueMode: MultiValueMode? {
+        return self._multiValueMode
     }
     
     public func build() throws -> GaussScoreFunction {
-        return GaussScoreFunction(withBuilder: self)
-    }
-}
+        return try GaussScoreFunction(withBuilder: self)
+    }
+}
+
+// MARK:- Exponential Decay Function Builder
 
 public class ExponentialDecayFunctionBuilder: ScoreFunctionBuilder {
     
-    public var field: String?
-    public var origin: String?
-    public var scale: String?
-    public var offset: String?
-    public var decay: Decimal?
-    public var isMultiValue: Bool = false
-    public var multiValueMode: DecayScoreFunction.MultiValueMode = .MIN
-    
-    typealias BuilderClosure = (ExponentialDecayFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _field: String?
+    private var _origin: String?
+    private var _scale: String?
+    private var _offset: String?
+    private var _decay: Decimal?
+    private var _multiValueMode: MultiValueMode?
+    
+    public init() {}
+    
+    public func set(field: String) -> ExponentialDecayFunctionBuilder {
+        self._field = field
+        return self
+    }
+    public func set(origin: String) -> ExponentialDecayFunctionBuilder {
+        self._origin = origin
+        return self
+    }
+    public func set(scale: String) -> ExponentialDecayFunctionBuilder {
+        self._scale = scale
+        return self
+    }
+    public func set(offset: String) -> ExponentialDecayFunctionBuilder {
+        self._offset = offset
+        return self
+    }
+    public func set(decay: Decimal) -> ExponentialDecayFunctionBuilder {
+        self._decay = decay
+        return self
+    }
+    public func set(multiValudMode: MultiValueMode) -> ExponentialDecayFunctionBuilder {
+        self._multiValueMode = multiValudMode
+        return self
+    }
+    
+    public var field: String? {
+        return self._field
+    }
+    public var origin: String? {
+        return self._origin
+    }
+    public var scale: String? {
+        return self._scale
+    }
+    public var offset: String? {
+        return self._offset
+    }
+    public var decay: Decimal? {
+        return self._decay
+    }
+    public var multiValueMode: MultiValueMode? {
+        return self._multiValueMode
     }
     
     public func build() throws -> ExponentialDecayScoreFunction {
-        return ExponentialDecayScoreFunction(withBuilder: self)
-    }
-    
-}
+        return try ExponentialDecayScoreFunction(withBuilder: self)
+    }
+    
+}
+
+// MARK:- Field Value Factor Function Builder
 
 public class FieldValueFactorFunctionBuilder: ScoreFunctionBuilder {
     
-    var field: String?
-    var factor: Decimal?
-    var modifier: FieldValueScoreFunction.Modifier?
-    var missing: Decimal?
-    
-    typealias BuilderClosure = (FieldValueFactorFunctionBuilder) -> Void
-    
-    init() {}
-    
-    convenience init(builderClosure: BuilderClosure) {
-        self.init()
-        builderClosure(self)
+    private var _field: String?
+    private var _factor: Decimal?
+    private var _modifier: FieldValueScoreFunction.Modifier?
+    private var _missing: Decimal?
+    
+    public init() {}
+    
+    public func set(field: String) -> FieldValueFactorFunctionBuilder {
+        self._field = field
+        return self
+    }
+    
+    public func set(factor: Decimal) -> FieldValueFactorFunctionBuilder {
+        self._factor = factor
+        return self
+    }
+    
+    public func set(modifier: FieldValueScoreFunction.Modifier) -> FieldValueFactorFunctionBuilder {
+        self._modifier = modifier
+        return self
+    }
+    
+    public func set(missing: Decimal) -> FieldValueFactorFunctionBuilder {
+        self._missing = missing
+        return self
+    }
+    
+    public var field: String? {
+        return self._field
+    }
+    public var factor: Decimal? {
+        return self._factor
+    }
+    public var modifier: FieldValueScoreFunction.Modifier? {
+        return self._modifier
+    }
+    public var missing: Decimal? {
+        return self._missing
     }
     
     public func build() throws -> FieldValueScoreFunction {
-        return FieldValueScoreFunction(withBuilder: self)
-    }
-    
-}
-
+        return try FieldValueScoreFunction(withBuilder: self)
+    }
+    
+}
+
+// MARK:- Weight Score Function
 
 public class WeightScoreFunction: ScoreFunction {
     public var name: String = "weight"
     
     var weight: Decimal
     
-    public init(withBuilder builder: WeightBuilder) {
+    public init(_ weight: Decimal) {
+        self.weight = weight
+    }
+    
+    internal init(withBuilder builder: WeightBuilder) throws {
+        
+        guard builder.weight != nil else {
+            throw ScoreFunctionBuilderError.missingRequiredField("weight")
+        }
+        
         self.weight = builder.weight!
     }
     

    var seed: Int
    var field: String
    
    public init(withBuilder builder: RandomScoreFunctionBuilder) {
        self.seed = builder.seed!
        self.field = builder.field!
    }
    
    public func toDic() -> [String : Any] {
        return [self.name: [RandomScoreFunction.SEED: self.seed, RandomScoreFunction.FIELD: self.field]]
    }
}

public class ScriptScoreFunction: ScoreFunction {
    
    private static let SOURCE = "source"
    private static let PARAMS = "params"
    
    public var name: String = "script_score"
    
    var source: String?
    var params: [String: Any] = [String: Any]()
    
    public init(withBuilder builder: ScriptScoreFunctionBuilder) {
        self.source = builder.script?.source
        if let params = builder.script?.params {
            self.params = params
        }
    }
    
    public func toDic() -> [String : Any] {
        var dic: [String: Any] = [String: Any]()
        if let source = self.source {
            dic[ScriptScoreFunction.SOURCE] = source
        }
        if params.isEmpty {
            dic[ScriptScoreFunction.PARAMS] = params
        }
        return [self.name: dic]
    }
}

public class LinearDecayScoreFunction: DecayScoreFunction {
    
    public init(withBuilder builder: LinearDecayFunctionBuilder) {
        super.init(type: .Linear, field: builder.field!, origin: builder.origin!, scale: builder.scale!, offset: builder.offset!, decay: builder.decay!, isMultiValue: builder.isMultiValue, multiValueMode: builder.multiValueMode)
    }
}

public class GaussScoreFunction: DecayScoreFunction {
    
    public init(withBuilder builder: GaussDecayFunctionBuilder) {
        super.init(type: .Linear, field: builder.field!, origin: builder.origin!, scale: builder.scale!, offset: builder.offset!, decay: builder.decay!, isMultiValue: builder.isMultiValue, multiValueMode: builder.multiValueMode)
    }
}

public class ExponentialDecayScoreFunction: DecayScoreFunction {
    
    public init(withBuilder builder: ExponentialDecayFunctionBuilder) {
        super.init(type: .Linear, field: builder.field!, origin: builder.origin!, scale: builder.scale!, offset: builder.offset!, decay: builder.decay!, isMultiValue: builder.isMultiValue, multiValueMode: builder.multiValueMode)
    }
}

public class DecayScoreFunction: ScoreFunction {
    

    }
    
    public enum Modifier: String {
        case none
        case log
        case log1p
        case log2p
        case ln
        case ln1p
        case ln2p
        case square
        case sqrt
        case reciprocal
    }
}

// MARK:- ScoreFunctionBuilder Error

/// Error(s) thrown by ScoreFunctionBuilder
public enum ScoreFunctionBuilderError: Error {
    case missingRequiredField(String)
}

//public class Script {
