import glob
import re

"""
def parse_z1(s):
    '''
    0008 0005       10 | specific_character_set               | CS | 1-n | "ISO_IR 192"

    '''
    pattern = '(?P<Grp>\d{4}) (?P<Elmt>\d{4})\s+(?P<Length>\d+) \|\s+(?P<Description>[^|]+?)\s+\| (?P<VR>..) \|\s+(?P<VM>\S+)\s+\|\s*(?P<Value>"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)'
    
    r = re.compile(pattern)
        
    return [m.groupdict() for m in r.finditer(s)]
        
    

def parse_z2(s):
    '''
    [ object, original_order ] = 1 ( 4, 4 )
    '''

    pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)'
    
    return re.findall(pattern, s, re.MULTILINE)    


def parse_z(s):
    
    pattern = '(?P<Grp>\d{4}) (?P<Elmt>\d{4})\s+(?P<Length>\d+) \|\s+(?P<Description>[^|]+?)\s+\| (?P<VR>..) \|\s+(?P<VM>\S+)\s+\|\s*(?P<Value>"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)'
    r = re.compile(pattern)
    ret1 = [m.groupdict() for m in r.finditer(s)]
    
    pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)'
    ret2 = re.findall(pattern, s, re.MULTILINE)
    
    return ret1, ret2
"""


class IMPAX_Description:
    def __init__(self, s):
            pattern = '(?P<Grp>\d{4}) (?P<Elmt>\d{4})\s+(?P<Length>\d+) \|\s+(?P<Description>[^|]+?)\s+\| (?P<VR>..) \|\s+(?P<VM>\S+)\s+\|\s*(?P<Value>"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)'
            r = re.compile(pattern)
            self.data1 = [m.groupdict() for m in r.finditer(s)]
            
            pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)'
            self.data2 = re.findall(pattern, s, re.MULTILINE)
            
            self.data = {}
            
            for elm in self.data2:
                self.data[elm[1]] = elm[2].replace('"', '')
                
            for elm in self.data1:
                if '...' not in elm['Value']:
                    self.data[elm['Description']] = elm['Value'].replace('"', '')
                
#             print self.data
#             exit() 

    def dump(self):
        return self.data1, self.data2
    
    def get_old(self, s):
        for elm in self.data2:
            if elm[1] == s:
                return elm[2].replace('"', '')
            
        for elm in self.data1:
            if elm['Description'] == s:
                return elm['Value'].replace('"', '')
            
        raise NameError('%s not found' % s)
    
    def get(self, s):
        if s in self.data:
#             print s, self.data[s]
            return self.data[s]
        
        raise NameError('%s not found' % s)
    
    def keys(self):
        return self.data.keys()
    
    def __sub__(self, other):
        sdata = {}
        for k in self.data:
            if k not in other.data:
#                 sdata[k] = (self.data[k], None)
                pass
            elif self.data[k] != other.data[k]: 
                sdata[k] = (self.data[k], other.data[k])
                
        for k in other.data:
            if k not in self.data:
#                 sdata[k] = (None, other.data[k])
                pass
            
        return sdata

class IMPAX_Series_one:
    def __init__(self, path):
        self.path = path
        ztxt = '%s/z.txt' % (path)
        with open(ztxt, 'r') as myfile:
            data=myfile.read()
        self.Description = IMPAX_Description(data)
        
    def direction(self):
        import numpy as np
        
        image_orientation_patient = self.Description.get('image_orientation_patient').split('\\')
        image_position_patient = self.Description.get('image_position_patient').split('\\')

        dir = [round(float(a)) for a in image_orientation_patient]
        
        pos = map(float, image_position_patient)
        
        dir2 = (abs(np.array(dir[:3])+np.array(dir[3:]))-1)*pos
        dir2 = dir2 / np.linalg.norm(dir2)

        print self.path
        print image_orientation_patient
        print image_position_patient
        print dir
        print dir2
               
        return dir + dir2.tolist()
        
        
    def write(self, filename):
        import SimpleITK
        
        print self.Description.get('image_number')
#         print self.Description.get('referenced_image_sequence')
#         print self.Description.get('source_image_sequence')
        
        files = glob.glob("%s/*.jpg" % self.path)
        files.sort()
    
        sreader1 = SimpleITK.ImageSeriesReader()
        sreader1.SetFileNames(files)
        img = sreader1.Execute()
        
        pixel_spacing = self.Description.get('pixel_spacing').split('\\')

        try:
            slice_spacing = float(self.Description.get('slice_spacing'))
        except:
            slice_spacing = float(self.Description.get('slice_thickness'))
            
        img.SetDirection(self.direction())

        img.SetSpacing((float(pixel_spacing[0]), float(pixel_spacing[1]), slice_spacing))
        
        SimpleITK.WriteImage(img, filename)
        
        print img.GetDirection()
        print

class IMPAX_Series:
    def __init__(self, path):
        self.DescriptionOrder = {}
        self.path = path
        files = glob.glob("%s/z*.txt" % self.path)
        
        for filename in files:
#             print filename
            m = re.search('z(.+).txt', filename)
            if m is None:
                continue
            f_number = int(m.group(1))
            print filename, f_number
            with open(filename, 'r') as myfile:
                data=myfile.read()
                
            d = IMPAX_Description(data)
            print d.get('image_number')

            d_number = int(d.get('image_number'))
            if d_number != f_number:
                raise NameError('File name: %s, Description: %d' % (filename, d_number))
            
            self.DescriptionOrder[f_number] = d
        
        self.images = sorted(self.DescriptionOrder.keys())
        self.Description = self.DescriptionOrder[self.images[0]]

        
    def direction_old(self):
        import numpy as np
        
        pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\')))
        pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\')))
#         dir2 = pos_z - pos_a
#         print pos_a, pos_z, dir2
#         dir2 = dir2 / np.linalg.norm(dir2)
#         dir2 = [round(a) for a in dir2]
        
        image_orientation_patient = self.Description.get('image_orientation_patient').split('\\')
        image_position_patient = self.Description.get('image_position_patient').split('\\')

        dir = [round(float(a)) for a in image_orientation_patient]
        
        pos = map(float, image_position_patient)
        
        dir2 = (abs(np.array(dir[:3])+np.array(dir[3:]))-1)*(pos_a - pos_z)
        dir2 = dir2 / np.linalg.norm(dir2)

        print self.path
        print image_orientation_patient
        print image_position_patient
        print dir
        print dir2
               
        return dir + dir2.tolist()

        
    def direction_old2(self):
        import numpy as np
        
#         print self.DescriptionOrder[self.images[0]].get('image_number'), self.DescriptionOrder[self.images[0]].get('image_position_patient')
#         print self.DescriptionOrder[self.images[-1]].get('image_number'), self.DescriptionOrder[self.images[-1]].get('image_position_patient')
        
        pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\')))
        pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\')))
        
        image_orientation_patient = self.Description.get('image_orientation_patient').split('\\')
        image_position_patient = self.Description.get('image_position_patient').split('\\')

        dir = [float(a) for a in image_orientation_patient]
        
        pos = map(float, image_position_patient)
        
#         dir2 = (pos_z - pos_a) * [1, -1, 1]/ (self.images[-1] - self.images[0])
        dir2 = (pos_z - pos_a) / (self.images[-1] - self.images[0])

        dir3 = np.array(dir+dir2.tolist())
        dir3 = dir3 / np.linalg.norm(dir3) 

        print self.path
        print image_orientation_patient
        print pos_a, pos_z
        print self.images
        print dir
        print dir2
        print dir3
               
        return dir3.tolist()


    def direction(self):
        import numpy as np
        
#         print self.DescriptionOrder[self.images[0]].get('image_number'), self.DescriptionOrder[self.images[0]].get('image_position_patient')
#         print self.DescriptionOrder[self.images[-1]].get('image_number'), self.DescriptionOrder[self.images[-1]].get('image_position_patient')
        
        pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\')))
        pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\')))
        
        image_orientation_patient = self.Description.get('image_orientation_patient').split('\\')
        image_position_patient = self.Description.get('image_position_patient').split('\\')

        dir = [round(float(a)) for a in image_orientation_patient]
#         dir = [float(a) for a in image_orientation_patient]
        
        pos = map(float, image_position_patient)
        
#         dir2 = (pos_z - pos_a) * [1, -1, 1]/ (self.images[-1] - self.images[0])
        dir2 = (pos_z - pos_a) / (self.images[-1] - self.images[0])
        
        dir2 = dir2 / np.linalg.norm(dir2)
        dir2 = [round(a) for a in dir2]
#         dir2 = [a for a in dir2]
        

        dir3 = np.array(dir+dir2)

        dir4 = np.linalg.inv(dir3.reshape(3,3)) 
        dir4 = np.transpose(dir3.reshape(3,3)) 

        print self.path
        print image_orientation_patient
        print pos_a, pos_z
        print self.images
        print dir
        print dir2
        print dir3
        print dir4

        print list(dir4.flat)
               
        return list(dir4.flat)
        
#         return dir3.tolist()

        
    def write(self, filename):
        import SimpleITK
        
        print self.Description.get('image_number')
#         print self.Description.get('referenced_image_sequence')
#         print self.Description.get('source_image_sequence')
        
        files = glob.glob("%s/*.jpg" % self.path)
        files.sort()
    
        sreader1 = SimpleITK.ImageSeriesReader()
        sreader1.SetFileNames(files)
        img = sreader1.Execute()
        
        pixel_spacing = self.Description.get('pixel_spacing').split('\\')

        try:
            slice_spacing = float(self.Description.get('slice_spacing'))
        except:
            slice_spacing = float(self.Description.get('slice_thickness'))
            
        img.SetDirection(self.direction())

        img.SetSpacing((float(pixel_spacing[0]), float(pixel_spacing[1]), slice_spacing))
        
        SimpleITK.WriteImage(img, filename)
        
        print img.GetDirection()
        print
        
    def get_description(self):
        return self.Description


if __name__ == "__main__":
    series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/2671292/20130417')
    series.write('/tmp/20130417.nii.gz')
    
    series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/2671292/20130417C')
    series.write('/tmp/20130417C.nii.gz')
    
    
    
#     series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20120815')
#     series.write('/tmp/20120815.nii.gz')
#     d1 = series.get_description()
# 
#     series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20120815C')
#     series.write('/tmp/20120815C.nii.gz')
#    
#     series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20160216')
#     series.write('/tmp/20160216.nii.gz')
# 
#     series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20160216C')
#     series.write('/tmp/20160216C.nii.gz')
#     d2 = series.get_description()
#     
#     import pprint
#     pp = pprint.PrettyPrinter(indent=4)

#     print d1-d2
#     pp.pprint(d1-d2)
    
    
    