// Autogenerated with DRAKON Editor 1.31


function BubleSorter_AfterSwap_default(self, array) {
    // item 204
    self.state = "AfterSwap";
}

function BubleSorter_AfterSwap_goNext(self, array) {
    // item 194
    if (self.context.reachedEnd()) {
        // item 200
        self.context.currentIndex(0)
        // item 199
        self.state = "NotSwapped";
    } else {
        // item 197
        if (self.context.outOfOrder()) {
            // item 202
            swap(self.context)
        } else {
            
        }
        // item 196
        move(self.context)
        // item 171
        self.state = "AfterSwap";
    }
}

function BubleSorter_CleanUp(self, array) {
    
}

function BubleSorter_NotSwapped_goNext(self, array) {
    // item 180
    if (self.context.reachedEnd()) {
        // item 205
        self.done = true
        // item 182
        self.state = null;
    } else {
        // item 184
        if (self.context.outOfOrder()) {
            // item 201
            swap(self.context)
            // item 187
            move(self.context)
            // item 188
            self.state = "AfterSwap";
        } else {
            // item 183
            move(self.context)
            // item 168
            self.state = "NotSwapped";
        }
    }
}

function BubleSorter_NotSwapped_init(self, array) {
    // item 185
    self.context = new SortContext()
    self.context.array(array)
    self.context.currentIndex(0)
    // item 179
    self.state = "NotSwapped";
}

function Partitioner_CleanUp(self, data) {
    
}

function Partitioner_Processing_default(self, data) {
    // item 324
    self.state = "Processing";
}

function Partitioner_Processing_goNext(self, data) {
    // item 322
    if (self.left > self.right) {
        // item 354
        self.result = self.right + 1
        self.done = true
        // item 332
        swapItems(
        	self.array,
        	self.end,
        	self.result
        )
        // item 333
        self.state = null;
    } else {
        // item 325
        var right = self.array[self.right]
        // item 327
        if (right < self.midValue) {
            // item 329
            swapItems(
            	self.array,
            	self.left,
            	self.right
            )
            // item 330
            self.left++
        } else {
            // item 331
            self.right--
        }
        // item 307
        self.state = "Processing";
    }
}

function Partitioner_Start_default(self, data) {
    // item 313
    self.state = "Start";
}

function Partitioner_Start_init(self, data) {
    // item 314
    self.array = data.array
    self.end = data.end
    // item 304
    self.mid = Math.floor(
    	(data.begin + data.end) / 2
    )
    // item 326
    self.midValue = self.array[self.mid]
    // item 315
    swapItems(
    	self.array,
    	self.mid,
    	data.end
    )
    // item 316
    self.left = data.begin
    self.right = data.end - 1
    // item 298
    self.state = "Processing";
}

function QuickSorter_CleanUp(self, array) {
    
}

function QuickSorter_Processing_default(self, array) {
    // item 388
    self.state = "Processing";
}

function QuickSorter_Processing_goNext(self, array) {
    // item 386
    if (self.tasks.length == 0) {
        // item 435
        self.done = true
        // item 397
        self.state = null;
    } else {
        // item 389
        var task = self.tasks.pop()
        // item 425
        var mid = partition(
        	self.array,
        	task.begin,
        	task.end
        )
        // item 426
        addTask(self, task.begin, mid - 1)
        // item 427
        addTask(self, mid + 1, task.end)
        // item 371
        self.state = "Processing";
    }
}

function QuickSorter_Start_default(self, array) {
    // item 377
    self.state = "Start";
}

function QuickSorter_Start_init(self, array) {
    // item 378
    self.array = array
    self.tasks = []
    // item 368
    addTask(
    	self,
    	0,
    	array.length - 1
    )
    // item 364
    self.state = "Processing";
}

function addTask(self, begin, end) {
    // item 409
    var count = end - begin + 1
    // item 4100001
    if (count < 2) {
        
    } else {
        // item 4100002
        if (count == 2) {
            // item 421
            if (self.array[begin] > self.array[end]) {
                // item 424
                swapItems(
                	self.array,
                	begin,
                	end
                )
            } else {
                
            }
        } else {
            // item 407
            self.tasks.push({
            	begin: begin,
            	end: end
            })
        }
    }
}

function bubbleSort(array) {
    // item 126
    var machine = new BubleSorter()
    // item 289
    runMachine(machine, array)
}

function move(self) {
    // item 219
    var i2 = self.currentIndex() + 1
    self.currentIndex(i2)
}

function partition(array, begin, end) {
    // item 340
    var machine = new Partitioner()
    // item 352
    var data = {
    	array: array, 
    	begin: begin,
    	end: end
    }
    // item 341
    runMachine(machine, data)
    // item 351
    return machine.result
}

function quickSort(array) {
    // item 433
    var machine = new QuickSorter()
    // item 434
    runMachine(machine, array)
}

function runMachine(machine, data) {
    // item 284
    machine.init(data)
    while (true) {
        // item 285
        if (machine.done) {
            break;
        } else {
            
        }
        // item 288
        machine.goNext()
    }
}

function swap(self) {
    // item 251
    swapItems(
    	self.array(),
    	self.currentIndex(),
    	self.nextIndex()
    )
}

function swapItems(array, red, black) {
    // item 249
    var redValue = array[red]
    var blackValue = array[black]
    // item 250
    array[red] = blackValue
    array[black] = redValue
}

function testPartition(array) {
    // item 347
    var old = array.slice()
    // item 348
    var mid = partition(array, 0, array.length - 1)
    // item 349
    console.log(old, mid, array)
    // item 350
    console.log()
}

function testSort(array) {
    // item 225
    var a1 = array.slice()
    var a2 = array.slice()
    // item 226
    bubbleSort(a1)
    quickSort(a2)
    // item 227
    console.log(array)
    console.log("bubble", a1)
    console.log("quick ", a2)
    // item 228
    console.log()
}

function SortContext__p_currentValue() {
    // item 137
    return this.array()[this.currentIndex()]
}

function SortContext__p_nextIndex() {
    // item 141
    return this.currentIndex() + 1
}

function SortContext__p_nextValue() {
    // item 145
    return this.array()[this.nextIndex()]
}

function SortContext__p_outOfOrder() {
    // item 156
    return this.currentValue() > this.nextValue()
}

function SortContext__p_reachedEnd() {
    // item 152
    return this.nextIndex() >= this.array().length
}

function SortContext() {
    this._array = null
    this.array = function(newValue) {
        if (typeof newValue != "undefined") {
            this._array = newValue
            this._currentValue = null
            this._nextValue = null
            this._outOfOrder = null
            this._reachedEnd = null
            return
        }
        return this._array
    }
    this._currentIndex = null
    this.currentIndex = function(newValue) {
        if (typeof newValue != "undefined") {
            this._currentIndex = newValue
            this._currentValue = null
            this._nextIndex = null
            this._nextValue = null
            this._outOfOrder = null
            this._reachedEnd = null
            return
        }
        return this._currentIndex
    }
    this._currentValue = null
    this.currentValue = function() {
        var value = this._currentValue
        if (value != null) {
            return value
        }
        value = SortContext__p_currentValue.call(this)
        this._currentValue = value
        return value
    }
    this._nextIndex = null
    this.nextIndex = function() {
        var value = this._nextIndex
        if (value != null) {
            return value
        }
        value = SortContext__p_nextIndex.call(this)
        this._nextIndex = value
        return value
    }
    this._nextValue = null
    this.nextValue = function() {
        var value = this._nextValue
        if (value != null) {
            return value
        }
        value = SortContext__p_nextValue.call(this)
        this._nextValue = value
        return value
    }
    this._outOfOrder = null
    this.outOfOrder = function() {
        var value = this._outOfOrder
        if (value != null) {
            return value
        }
        value = SortContext__p_outOfOrder.call(this)
        this._outOfOrder = value
        return value
    }
    this._reachedEnd = null
    this.reachedEnd = function() {
        var value = this._reachedEnd
        if (value != null) {
            return value
        }
        value = SortContext__p_reachedEnd.call(this)
        this._reachedEnd = value
        return value
    }
}

function BubleSorter() {
  var _self = this;
  _self.type_name = "BubleSorter";
  _self.state = "NotSwapped";
  _self.goNext = function(array) {
    var _state_ = _self.state;
    if (_state_ == "NotSwapped") {
      return BubleSorter_NotSwapped_goNext(_self, array);
    }
    else if (_state_ == "AfterSwap") {
      return BubleSorter_AfterSwap_goNext(_self, array);
    }
    return null;
  };
  _self.init = function(array) {
    var _state_ = _self.state;
    if (_state_ == "NotSwapped") {
      return BubleSorter_NotSwapped_init(_self, array);
    }
    else if (_state_ == "AfterSwap") {
      return BubleSorter_AfterSwap_default(_self, array);
    }
    return null;
  };
}

function Partitioner() {
  var _self = this;
  _self.type_name = "Partitioner";
  _self.state = "Start";
  _self.goNext = function(data) {
    var _state_ = _self.state;
    if (_state_ == "Start") {
      return Partitioner_Start_default(_self, data);
    }
    else if (_state_ == "Processing") {
      return Partitioner_Processing_goNext(_self, data);
    }
    return null;
  };
  _self.init = function(data) {
    var _state_ = _self.state;
    if (_state_ == "Start") {
      return Partitioner_Start_init(_self, data);
    }
    else if (_state_ == "Processing") {
      return Partitioner_Processing_default(_self, data);
    }
    return null;
  };
}

function QuickSorter() {
  var _self = this;
  _self.type_name = "QuickSorter";
  _self.state = "Start";
  _self.goNext = function(array) {
    var _state_ = _self.state;
    if (_state_ == "Start") {
      return QuickSorter_Start_default(_self, array);
    }
    else if (_state_ == "Processing") {
      return QuickSorter_Processing_goNext(_self, array);
    }
    return null;
  };
  _self.init = function(array) {
    var _state_ = _self.state;
    if (_state_ == "Start") {
      return QuickSorter_Start_init(_self, array);
    }
    else if (_state_ == "Processing") {
      return QuickSorter_Processing_default(_self, array);
    }
    return null;
  };
}


testSort([])
testSort([1, 1, 1, 1, 1])
testSort([1, 2, 3, 4, 5])
testSort([5, 4, 3, 2, 1])
testSort([13, 30, 1, 3, 5, 2, 3])

testSort([1, 1, 1, 1])
testSort([1, 1, 1, 1, 1])

testSort([5, 4, 3, 2])
testSort([2, 2, 2, 3])
testSort([3, 3, 3, 2])
testSort([3, 5, 1, 2])



testPartition([1, 1, 1])
testPartition([1, 2, 3])
testPartition([5, 4, 3])
testPartition([2, 2, 3])
testPartition([3, 3, 2])
testPartition([3, 5, 2])

testPartition([1, 1, 1, 1])
testPartition([1, 1, 1, 1, 1])

testPartition([5, 4, 3, 2])
testPartition([2, 2, 2, 3])
testPartition([3, 3, 3, 2])
testPartition([3, 5, 1, 2])
