 /*
-Copyright (c) 2015 Marko Sabotin
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
+ Copyright (c) 2015 Marko Sabotin
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
 
 import UIKit
 import SpriteKit

    }
    
    // Black hole variant
    private func drawBlackHoleLayerOne(ctx:CGContextRef)
    {
        let blackHolerFactor:CGFloat = 1.0 + (Helper.random01CGFloat() * 0.5)
        let properBlackHole = Helper.fiftyFifty()
        
        if Helper.fiftyFifty()
        {
            setRandomStroke(ctx)
        }
        else
        {
            setRandomStroke2(ctx)
        }
        
        setRandomFillLighter(ctx)
        setRandomLineWidth(ctx)
        
        let howMany = Helper.randomBetween(FactorBlackHoleMin, max: FactorBlackHoleMax, includeMax: false)
        var holes:[CGRect] = []
        var step:CGFloat = (BackDimensionMax / 2.0) / CGFloat(howMany)
        let centerOut = Helper.fiftyFifty()

        start = 0.0
        
        let megaCurves = Helper.fiftyFifty()
        let megaMiddlePoint = CGPoint(x: centerBack.x - centerBack.x, y: centerBack.y - centerBack.y)
        let controlPointX2:CGFloat = BackRect.minX + (Helper.random01CGFloat() * BackRect.width)
        let controlPointY2:CGFloat = BackRect.minY + (Helper.random01CGFloat() * BackRect.height)
        let controlPoint2 = CGPoint(x: controlPointX2 - centerBack.x, y: controlPointY2 - centerBack.y)
        
        while start <= howLong
        {
            if fullRandomize
            {
                blackHolesRandomizations(ctx: ctx, randomize1: randomize1, randomize2: randomize2, randomize3: randomize3, randomize4: randomize4)
            }
            
            ctx.rotate(by: angle)
            ctx.beginPath()
            
            if megaCurves
            {
                ctx.move(to: startPoint)
                ctx.addQuadCurve(to: megaMiddlePoint, control: controlPoint)
                ctx.addQuadCurve(to: endPoint, control: controlPoint2)
            }
            else
            {
                ctx.move(to: startPoint)
                ctx.addQuadCurve(to: endPoint, control: controlPoint)
            }
            
            if drawFillStroke
            {
                ctx.drawPath(using: .fillStroke)
            }
            else
            {
                ctx.strokePath()
            }
            
            start += angle
        }
        ctx.restoreGState()
    }
    
    private func carpetsRandomizations(ctx:CGContext, randomize1:Bool, randomize2:Bool, randomize3:Bool)
    {
        if randomize1
        {
            setRandomShadow(ctx: ctx)
        }
        
        if randomize2
        {
            setRandomLineWidth(ctx: ctx)
        }
        
        if randomize3
        {
            if Helper.fiftyFifty()
            {
                setRandomStroke(ctx: ctx)
            }
            else
            {
                setRandomStroke2(ctx: ctx)
            }
        }
    }
    
    
    // NOTE: Carpets
    private func drawCarpet(ctx:CGContext)
    {
        let step:CGFloat = BackDimensionMax / CGFloat(Helper.randomBetween(min: Int(FactorLinesStepperMin), max: Int(FactorLinesStepperMax), includeMax: false))
        var carpets:[[CGPoint]] = []
        
        var i = BackRect.minX
        
        while i <= BackRect.maxX {
            carpets.append([CGPoint(x: i, y: BackRect.minY), CGPoint(x: i, y: BackRect.maxY)])
            i += step
        }
        
        var j = BackRect.minY
        
        while j <= BackRect.maxY {
            carpets.append([CGPoint(x: BackRect.minX, y: j), CGPoint(x: BackRect.maxX, y: j)])
            j += step
        }
        
        // NOTE: !!! RANDOM SHUFFLE POINTS
        carpets.shuffle()
        
        setRandomStroke2(ctx: ctx)
        setRandomLineWidth(ctx: ctx)
        
        let fullRandomize = Helper.fiftyFifty()
        let randomize1 = Helper.fiftyFifty()
