#!/usr/bin/env python
#coding=utf-8
#
#
from Cocoa import *
import os

genericIconData = NSWorkspace.sharedWorkspace().iconForFileType_("alsdkfja").TIFFRepresentation()
iconList = set()


def iconpath(UTI):
	return "/tmp/UTI-Icons/" + UTI + ".png"


def saveImage(image, path):
	tiffData = image.TIFFRepresentation()
	bitmap = NSBitmapImageRep.imageRepWithData_(tiffData)
	imageData = bitmap.representationUsingType_properties_(NSPNGFileType, {})
	imageData.writeToFile_atomically_(path, True)


def iconsForUTIs():
	for UTI in conformanceDict.iterkeys():
		pool = NSAutoreleasePool.alloc().init()
		image = NSWorkspace.sharedWorkspace().iconForFileType_(UTI)
		if image != None:
			imageData = image.TIFFRepresentation()
			if imageData.isEqualToData_(genericIconData) is not True:
				for rep in image.representations():
					if rep.size().height > 128.0:
						image.removeRepresentation_(rep)
		
				path = iconpath(UTI)
				saveImage(image, path)
				iconList.add(UTI)
		pool.release()			


def UTIsFromPlist(path):
	result = []
	plist = NSDictionary.dictionaryWithContentsOfFile_(path)	
	
	if plist != None:
		if plist.has_key("UTExportedTypeDeclarations"):
			result += plist["UTExportedTypeDeclarations"]
		if plist.has_key("UTImportedTypeDeclarations"):
		 	result += plist["UTImportedTypeDeclarations"]
	else:
		print "problem reading file: " + path
	
	return result



def writeDOT (array):
	global dotfile
	for UTI in array:
		conformances = conformanceDict[UTI]
		dotfile += ['"', UTI, '"']

		if doesConform(UTI, "public.data", []):
			if doesConform (UTI, "com.pkware.zip-archive", []) or doesConform(UTI, "public.zip-archive", []):
				style = ", fillcolor=red, style=filled"
			else:
				style = ", fillcolor=gold, style=filled"
		elif doesConform(UTI, "com.pkware.zip-archive", []) or doesConform(UTI, "public.zip-archive", []):
			style = ", fillcolor=orange, style=filled"
		else:
			style = ", fillcolor=white, style=filled"
	
		if doesConform(UTI, "com.apple.package", []) and doesConform(UTI, "public.composite-content", []):
			style += ", shape=pentagon"
		elif doesConform(UTI, "com.apple.package", []):
			style += ", shape=box"
		elif doesConform(UTI, "public.composite-content", []):
			style += ", shape=octagon"
		else: 
			style += ", shape=none"

		if UTI in SystemUTIs:
			style += ", fontcolor=blue"
		elif UTI in LibraryUTIs:
			style += ", fontcolor=black"
		else:
			style += ", fontcolor=grey"

		path = iconpath(UTI)
		if os.access(path, os.F_OK):
			style += ', image="' + path + '", imagescale=true'
		dotfile += [" [fontsize=32", style, "];\n"]

		for conformance in conformances:
			if conformance not in omissions:
				dotfile += ['"', conformance, '"', ' -> ', '"',  UTI, '" [color=gray, dir=back];\n']


def subgraphForArray(array, name):
	global dotfile
	dotfile += ["subgraph cluster_", name, "{\n", "label = \"", name, "\";\n", "color=lightgrey;\n"]
	writeDOT(array)
	dotfile += ["}\n"]


def doesConform(myUTI, baseUTI, seenbefore):
	result = False
	seenbefore += [myUTI]
	if conformanceDict.has_key(myUTI):
		for conformance in conformanceDict[myUTI]:
			if conformance == baseUTI:
				return True
			if conformance not in seenbefore:
				result = doesConform(conformance, baseUTI, seenbefore)
	return result


def isSingleItem(myUTI):
	for conformance in conformanceDict[myUTI]:
		if conformance not in omissions:
			return False
	
	for conformance in conformanceDict.itervalues():
		if myUTI in conformance:
			return False
	return True





# vv Next line: just use Core Types
#plists = ("/System/Library/CoreServices/CoreTypes.bundle/Contents/Info.plist")
# vv Next line: use all Info.plists known to locate
#plists = os.popen("locate Info.plist").read()
# vv Next lines: use file with paths of Info.plists, e.g. 
# vv 	created by "sudo find -s / | grep Info.plist | sed 's/\(.*\)/"\1"/g' | xargs -L 5 grep --files-with-matches TypeDeclarations"
f = open ("Info-Plists.text")
plists = f.read()
f.close()

omissions = ["public.data", "com.apple.package", "public.composite-content", "public.content", "com.pkware.zip-archive", "public.zip-archive"]
conformanceDict = {}
MSs = set()
AVs = set()
Images = set()
Executables = set()
SingleItems = set()
SourceCodes = set()
Texts = set()
General = set()
SystemUTIs = []
LibraryUTIs = []

paths = plists.split("\n")

for path in paths:
	types = UTIsFromPlist(path)
	for type in types:
		UTI = type["UTTypeIdentifier"]
		conformsTo = []

		if type.has_key("UTTypeConformsTo"):
			conformsTo = type["UTTypeConformsTo"]		
			if isinstance(conformsTo, unicode):
				conformsTo = NSArray.arrayWithObject_(conformsTo)
			if conformanceDict.has_key(UTI):
				conformances = conformanceDict[UTI]
				for newConformance in conformsTo:
					if newConformance not in conformances:
						conformances = conformances.arrayByAddingObject_(newConformance)
				conformsTo = conformances
		
		conformanceDict[UTI] = conformsTo

		if path.startswith("/System"):
			SystemUTIs += [UTI]
		elif path.startswith("/Library"):
			LibraryUTIs += [UTI]



		if isSingleItem(UTI):
			SingleItems.add(UTI)
		elif UTI.startswith("com.microsoft"):
			MSs.add(UTI)
		elif doesConform(UTI, "public.audiovisual-content", []):
			AVs.add(UTI)
		elif doesConform(UTI, "public.image", []):
			Images.add(UTI)
		elif doesConform(UTI, "public.executable", []):
			Executables.add(UTI)
		elif doesConform(UTI, "public.source-code", []):
			SourceCodes.add(UTI)
		elif doesConform(UTI, "public.text", []):
			Texts.add(UTI)
		else:
			General.add(UTI)





dotfile = ["""digraph UTI_Conformances {
ranksep=7;
nodesep=2;
overlap=vpsc;
concentrate=true;
size="20.0,20.0";
"""]

subgraphForArray(Executables, "Executables")
subgraphForArray(Texts, "Text")
subgraphForArray(Images, "Images")
subgraphForArray(AVs, "SoundAndVision")
subgraphForArray(SourceCodes, "Code")
subgraphForArray(MSs, "Microsoft")
writeDOT(General)
#subgraphForArray(SingleItems, "Lonely") 

dotfile += ["}"]

dotfilestring = ''.join(dotfile)

f = open("/tmp/UTIGraph.gv", "w")
f.write(dotfilestring)
f.close()


iconsForUTIs()

os.popen("""twopi -Nfontname="Helvetica" -Tpdf /tmp/UTIGraph.gv > /tmp/UTIs.pdf""")

