import vector

def missing is public, readable = object{
    method asString->String{"-"}
}

type Iterator = {
    reset->Void
    hasNext->Boolean
    get->T
    next->T}

type Vector = {
    size->Number
    isEmpty->Boolean
    clear->Void
    contains(_:T)->Boolean
    addFirst(_:T)->Void
    addLast(_:T)->Void
    firstElement->T
    lastElement->T
    removeFirst->T
    removeLast->T
    removeValue(_:T)->T
    indexOf(_:T)->Number
    at(_:Number)->T
    setValue(_:T)at(_:Number)->T
    add(_:T)at(_:Number)->Void
    removeFromIndex(_:Number)->T
    iterator->Iterator
    asString->String
    forEachDo(_:Block)->Void
    map(_:Block)->Vector
    ensureCapacity(_:Number)->Void
    capacity->Number
    copyInto(_)->Void
    indexOf(_:T)startingFrom(_:Number)->Number
    setSize(_:Number)->Void
    trimToSize->Void}

type Matrix = {
    atRow(_:Number)Col(_:Number)->T
    setValue(_:T)atRow(_:Number)Col(_:Number)->Void
    addRowAt(_:Number)->Void
    addColAt(_:Number)->Void
    removeRowAt(_:Number)->Vector
    removeColAt(_:Number)->Vector
    columns->Number
    rows->Number
    asString->String}

method new->Matrix is public{MatrixClass.new(0, 0)}

method withRows(h:Number)columns(w:Number)->Matrix is public{
    if((h >= 0) && (w >= 0)) then {MatrixClass.new(h, w)}
    else{
        print "Must have non-negative rows and columns"
        new}
}

class MatrixClass.new(h:Number, w:Number) {

    var height:Number is readable := h

    var width:Number is readable:= w

    var index:Vector is readable := vector.withSize(height)

    for(1..height) do {i->
        var theRow:Vector := vector.withSize(width)
        index.addLast(theRow)
        for(1..width) do {j-> theRow.addLast(missing)}
    }

    // Fetch element from matrix
    // @pre 0 < row <= height, 0 < col <= width
    // @post @return object at (row, col)
    // @param row the row of the element 
    // @param col the column of the element
    method atRow(row:Number)Col(col:Number)->Dynamic is public{
        if((0 < row)&&(row <= height)&&(0 < col)&&(col <= width)) then{
            index.at(row).at(col)}
        else{
            print "Invalid index"
            missing}
    }

    // Change value at location (row, col)
    // @pre 0 < row <= height, 0 < col <= width
    // @post changes location (row, col) to value
    // @param value the new object reference
    // @param row the row of value to be changed
    // @param col the column of value to be changed
    method setValue(value)atRow(row:Number)Col(col:Number)->Void is public{
        if((0 < row)&&(row <= height)&&(0 < col)&&(col <= width)) then{
            index.at(row).setValue(value)at(col)}
        else{print "Invalid index"}
    }

    // Add a new row, whose index will be r
    // @pre 0 < r <= height + 1
    // @post inserts row of null values to be row r
    // @param r the index of the newly inseted row
    method addRowAt(r:Number)->Void is public{
        if((0 < r) && (r <= (height + 1))) then{
            height := height + 1
            var theRow:Vector := vector.withSize(width)
            for(1..width) do {i->theRow.addLast(missing)}
            index.add(theRow)at(r)}
        else{print "Invalid row index"}
    }

    // Add a new column, whose index will be c
    // @pre 0 < c <= width + 1
    // @post inserts column of null values to be column c
    // @param c the index of the newly inserted column
    method addColAt(c:Number)->Void is public{
        if((0 < c) && (c <= (width + 1))) then{
            width := width + 1
            for(1..height) do {i->
                index.at(i).add(missing)at(c)}
        }
        else{print "Invalid column index"}
    }

    // Remove row whose index is r.
    // The row is returned as a vector.
    // @pre 0 < r <= height
    // @post removes row r and returns it
    // @param r the index of to-be-removed row
    // @return vector of values once in row
    method removeRowAt(r:Number)->Vector is public{
        if((0 < r) && (r <= height)) then{
            var result:Vector := index.at(r)
            height := height - 1
            index.removeFromIndex(r)
            result}
        else{
            print "Invalid row index"
            vector.withSize(width)}
    }
    
    // Remove column whose index is c
    // @pre 0 < c <= width
    // @post removes column c and returns it as vector
    // @param c the index of column to-be-removed
    // @return removes row r and returns it as a vector
    method removeColAt(c:Number)->Vector is public{
        if((0 < c) && (c <= width)) then{
            var result:Vector := vector.withSize(height)
            width := width - 1
            for(1..height) do{i->
                var theRow:Vector := index.at(i)
                result.addLast(theRow.at(c))
                theRow.removeFromIndex(c)}
            result}
        else{
            print "Invalid column index"
            vector.withSize(height)}
    }
    
    // @post @return number of columns in matrix
    method columns->Number is public{width}

    // @post @return number of rows in matrix
    method rows->Number is public{height}

    // @post @return string representation of matrix
    method asString->String is public{
        var str:String := "
            for(1..width) do {j->
                str := str ++ " "}
            str := str ++ "\n"}
        return str ++ ">"}          
}