#!/usr/bin/python

# xmerge.py - merge yvals to an x value
# Ian Wienand <ianw@ieee.org>
# http://www.wienand.org
# Released to the public domain

import sys, string, re, fileinput
from optparse import OptionParser

class DataFile:
    def __init__(self, filename, thedict, fileno, nelem, zeropad, delim):
        self.filename = filename
        self.thedict = thedict
        self.fileno = fileno
        self.nelem = nelem
        self.zeropad = zeropad
        self.delim = delim
        self.lineno = 0

    def readfile(self):
        try:
            f = open(self.filename, 'r')
        except:
            print "Can't open input file " + self.filename
            sys.exit(2)
        
        while 1:
            line = f.readline().strip()
            if not line: break
            else: self.lineno = self.lineno + 1
            values = line.split(self.delim)
            if (len(values[1:]) < 1):
                return ('delimerr', self.lineno)
            if (self.nelem < len(values[1:])):
                return ('yvalerr', self.lineno)

            #zero pad
            for i in range(self.nelem - len(values[1:])):
                values.append(self.zeropad)
            posdict = self.thedict.setdefault(values[0],{})
            posdict[self.fileno] = values[1:]
            #print self.thedict                                     

        return('OK', 0)
    
    def getname(self):
        return self.filename

def main():

    thedict = {}
    files = []

    usage = "usage: %prog [options] file1 file2 [file3 ... filen]" 
    parser = OptionParser(usage)
    parser.add_option("-i", "--inputdeliminator", dest="inputdeliminator",
                      help="Deliminator between input fields", default=',', action="store")
    parser.add_option("-y", "--nyvals", dest="nyvals", action="store",
                      help="Number of y values", default=0, type='int')
    parser.add_option("-d", "--outputdeliminator", dest="outputdeliminator", action="store",
                      help="Delminiator between output fields", default=',')
    parser.add_option("-z", "--zero", dest="zero", action="store",
                      help="Value for missing/zero elements", default='0')

    (options, args) = parser.parse_args()

    if len(args) < 2:
        print "Please specify at least two files to merge"
        sys.exit(1)

    #if we have no yvals argument open the first file and take a guess
    try:
        f = open(args[0], 'r')
    except:
        print "Can't open input file " + args[0]
        sys.exit(2)

    if not options.nyvals:
        line = f.readline().strip()
        if not line:
            print "Invalid datafile " + f.name()
        values = line.split(',')
        options.nyvals = len(values[1:])
        if options.nyvals == 0:
            print "Can not guess nyvals; please specify"
            sys.exit(2)

    #setup a DataFile object for each given file
    for i in range(0, len(args)):
        files.append(DataFile(args[i], thedict, i, options.nyvals, options.zero, options.inputdeliminator))

    for file in files:
        (err, lineno) = file.readfile() 
        if err in "yvalerr":
            print "Too many yvals in input file " + file.getname() + " : line " + `lineno`
            print "Please specify correct nyvals to command"
            sys.exit(2)
        if err in "delimerr":
            print "Error processing input file " + file.getname() + " : line " + `lineno`
            print "Error parsing line"
            sys.exit(2);

    for xval,values in thedict.iteritems():
        line = xval 
        #go through each input file
        for i in range(0, len(args)):
            #see if it has an entry for this xval, if so put it in, otherwise
            #pad it out with the zero elements. 
            try:
                for yval in thedict[xval][i]:
                    line = line + options.outputdeliminator + yval 
            except:
                padline=''
                for i in range(0, options.nyvals):
                    padline = padline + options.outputdeliminator + options.zero
                line = line + padline
            
        print line
              
if __name__ == '__main__':
	main()

        

