#!/usr/bin/python

import sys
import os
import stat
import errno
import time
from fuse import Operations, FUSE, FuseOSError
import dft

class DICOMFS(Operations):

	def __init__(self, dicom_path):
		Operations.__init__(self)
		self.dicom_path = dicom_path
		self.fhs = {}
		return

	def get_paths(self):
		paths = {}
		for study in dft.get_studies(self.dicom_path):
			paths.setdefault(study.patient_name, {})
			pd = paths[study.patient_name]
			patient_info = 'patient information\n'
			patient_info = 'name: %s\n' % study.patient_name
			patient_info += 'ID: %s\n' % study.patient_id
			patient_info += 'birth date: %s\n' % study.patient_birth_date
			patient_info += 'sex: %s\n' % study.patient_sex
			pd['INFO'] = patient_info.encode('ascii', 'replace')
			study_datetime = '%s_%s' % (study.date, study.time)
			study_info = 'study info\n'
			study_info += 'UID: %s\n' % study.uid
			study_info += 'date: %s\n' % study.date
			study_info += 'time: %s\n' % study.time
			study_info += 'comments: %s\n' % study.comments
			d = {'INFO': study_info.encode('ascii', 'replace')}
			for series in study.series:
				series_info = 'series info\n'
				series_info += 'UID: %s\n' % series.uid
				series_info += 'number: %s\n' % series.number
				series_info += 'description: %s\n' % series.description
				series_info += 'rows: %d\n' % series.rows
				series_info += 'columns: %d\n' % series.columns
				series_info += 'bits allocated: %d\n' % series.bits_allocated
				series_info += 'bits stored: %d\n' % series.bits_stored
				series_info += 'storage instances: %d\n' % len(series.storage_instances)
				d[series.number] = {'INFO': series_info.encode('ascii', 'replace'), 
				                    '%s.nii' % series.number: (series.nifti_size, series.as_nifti), 
				                    '%s.png' % series.number: (series.png_size, series.as_png)}
			pd[study_datetime] = d
		return paths

	def match_path(self, path):
		wd = self.get_paths()
		if path == '/':
			print 'return root'
			return wd
		for part in path.lstrip('/').split('/'):
			print path, part
			if part not in wd:
				raise FuseOSError(errno.ENOENT)
			wd = wd[part]
		print 'return'
		return wd

	def readdir(self, path, fh):
		print 'readdir'
		print path
		matched_path = self.match_path(path)
		print 'match', matched_path
		fnames = [ k.encode('ascii', 'replace') for k in matched_path.keys() ]
		fnames.append('.')
		fnames.append('..')
		return fnames
    
	def getattr(self, path, fh):
		print 'getattr'
		print 'path:', path
		matched_path = self.match_path(path)
		print matched_path
		now = time.time()
		if isinstance(matched_path, dict):
			return {'st_mode': stat.S_IFDIR | 0755, 
		        	'st_ctime': now, 
		        	'st_mtime': now, 
		        	'st_atime': now, 
		        	'st_uid': 501, 
		        	'st_gid': 501, 
		        	'st_nlink': len(matched_path)}
		if isinstance(matched_path, str):
			return {'st_mode': stat.S_IFREG | 0644, 
		        	'st_ctime': now, 
		        	'st_mtime': now, 
		        	'st_atime': now, 
		        	'st_uid': 501, 
		        	'st_gid': 501, 
		        	'st_size': len(matched_path), 
			        'st_nlink': 1}
		if isinstance(matched_path, tuple):
			return {'st_mode': stat.S_IFREG | 0644, 
		        	'st_ctime': now, 
		        	'st_mtime': now, 
		        	'st_atime': now, 
		        	'st_uid': 501, 
		        	'st_gid': 501, 
		        	'st_size': matched_path[0](), 
			        'st_nlink': 1}
		raise FuseOSError(errno.ENOENT)
    
	def open(self, path, flags):
		print 'open'
		print path
		matched_path = self.match_path(path)
		for i in xrange(1, 10):
			if i not in self.fhs:
				if isinstance(matched_path, str):
					self.fhs[i] = matched_path
				elif isinstance(matched_path, tuple):
					self.fhs[i] = matched_path[1]()
				else:
					raise FuseOSError(errno.EFTYPE)
				return i
		raise FuseOSError(errno.ENFILE)

	def read(self, path, size, offset, fh):
		print 'read'
		print path
		print size
		print offset
		print fh
		return self.fhs[fh][offset:offset+size]

	def release(self, path, fh):
		print 'release'
		print path
		print fh
		del self.fhs[fh]
		return
    
progname = os.path.basename(sys.argv[0])
if len(sys.argv) != 3:
	sys.stderr.write('usage: %s <directory containing DICOMs> <mount point>\n' % progname)
	sys.exit(1)

# foreground
# debug
fuse = FUSE(DICOMFS(sys.argv[1]), sys.argv[2], foreground=True, debug=False)

# eof
