# matm3.py
# Written by Todd Wareham for CS 2500
"""
Given the name of a textfile of commands (one per line), for a 2D integer
 matrix manipulation system, execute these commands and print results
 or error messages to stndard output as appropriate.
 
For a full description of this system, please see the on-line description of
 Question #2 in Assignment #4.

This script is a vraiant of matm2.py (answer to Assignment #6, Question #2)
 which places the interpretation-loop from the main program in a function
 interpret. This is done to allow profiling of the runtimes of the various
 functions in this script via script profile_matm3.py.
"""

import sys


def getMatrixIndex(matList, matName):
    for i in range(0,len(matList)):
        if matList[i][0] == matName:
            return i
    return -1
    

def readMatrix(matList, matName):
##  Read matrix from file matName and store in matList.
    numCol = numRow = 0
    curMatrix = []
    for row in file(matName + ".mat"):
        numCol = len(row.split())
        numRow = numRow + 1
        curMatrix.append([int(x) for x in row.split()])
        
## Store matrix in matList, overwriting stored matrix
##  with the same name if necessary.

    index = getMatrixIndex(matList, matName)
    if (index == -1):
        matList.append([matName, numRow, numCol, curMatrix])
    else:
        matList[index] = [matName, numRow, numCol, curMatrix]

    return
        

def getMatrixString(matList, matName):
    index = getMatrixIndex(matList, matName)
    matString = ""
    if index != -1:
        for row in matList[index][3]:
            matString += (" ".join([str(x) for x in row]) + "\n")
    return matString


def getMatrixDimensions(matList, matName):
    index = getMatrixIndex(matList, matName)
    if index == -1:
        return -1, -1
    else:
        return matList[index][1], matList[index][2]


def incMatrix(matList, matName, inc):
    index = getMatrixIndex(matList, matName)
    if index != -1:
        for i in range(0,len(matList[index][3])):
            for j in range(0,len(matList[index][3][0])):
                matList[index][3][i][j] += inc
        return True
    return False


def appendRows(matList, matName1, matName2):
    index1 = getMatrixIndex(matList, matName1)
    index2 = getMatrixIndex(matList, matName2)
    if (index1 != -1) and (index2 != -1) and \
       (matList[index1][2] == matList[index2][2]):
        for i in range(0, len(matList[index1][3])):
            matList[index2][3].append(matList[index1][3][i][:])
        matList[index2][1] += matList[index1][1]
        return True
    return False


def appendColumns(matList, matName1, matName2):
    index1 = getMatrixIndex(matList, matName1)
    index2 = getMatrixIndex(matList, matName2)
    if (index1 != -1) and (index2 != -1) and \
       (matList[index1][1] == matList[index2][1]):
        for i in range(0, len(matList[index1][3])):
            matList[index2][3][i].extend(matList[index1][3][i][:])
        matList[index2][2] += matList[index1][2]
        return True
    return False


def interpret(commandfile):

    matList = []

    for line in file(commandfile):

        print ">>> " + line.rstrip()

        command = line.split()

##
## Process matrix read-in and storage command.
##

        if ((len(command) == 2) and (command[0] == "read")):

            readMatrix(matList, command[1])

##
## Process stored matrix print command.
##

        elif ((len(command) == 2) and (command[0] == "print")):

            matString = getMatrixString(matList, command[1])
            if matString:
                print matString.rstrip()
            else:
                print "Matrix not found"

##
## Process matrix-dimensions print command.
##

        elif ((len(command) == 2) and (command[0] == "dimensions")):

            numRow, numCol = getMatrixDimensions(matList, command[1])
            if numRow == -1:
                print "Matrix not found"
            else:
                print "# rows = ", numRow, "/ # columns = ", numCol

##
## Process stored matrix element-increment command.
##

        elif ((len(command) == 4) and (command[0] == "add") and (command[2] == "to")):

            if not incMatrix(matList, command[3], int(command[1])):
                print "Matrix not found"

##
## Process stored-matrix row- and column-append commands.
##

        elif ((len(command) == 6) and (command[0] == "append") and 
              (command[2] == "of") and (command[4] == "to") and
              (command[1] in ["rows", "columns"])):

            matName1 = command[3]
            matName2 = command[5]

            if getMatrixIndex(matList, matName1) == -1:
                print "Source matrix not defined"
            elif getMatrixIndex(matList, matName2) == -1:
                print "Target matrix not defined"
            elif command[1] == "rows":
                if not appendRows(matList, matName1, matName2):
                    print "Column dimensions do not match"
            elif command[1] == "columns":
                if not appendColumns(matList, matName1, matName2):
                    print "Row dimensions do not match"
    
        else:
            print "Invalid command"

    return



if __name__ == "__main__":

    if len(sys.argv) != 2:
        print "usage: ", sys.argv[0], " commandfile"
        sys.exit(1)

    interpret(sys.argv[1])

