import subprocess, marshal, os, stat, sys


g_bPerforceVerbose = False


# Make all lowercase and forward slashes.
def FixFilename( f ):
	return f.replace( '\\', '/' ).lower()



def SetPerforceVerbose( bVerbose ):
	global g_bPerforceVerbose
	g_bPerforceVerbose = bVerbose


def CheckPerforceReturn( cmd ):
	po = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
	sStdout = po.stdout.read()
	sStderr = po.stderr.read()
	ret = po.wait()
	if ret != 0:
		print >>sys.stderr, "A command returned %d: %s\nstdout = %s\nstderr = %s" % (ret, cmd, sStdout, sStderr)
		sys.exit( ret )
	


def ReadPerforceOutput( cmd, bCheckReturn=True ):
	if g_bPerforceVerbose:
		print "Running: " + cmd
		
	po = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE )
	
	results = []
	try:
		while True:
			try:
				entry = marshal.load(po.stdout)
			except ValueError:
				print '----------------------------------------------'
				print 'Marshal.load(po.stdout) got ValueError'
				print 'Next data:'
				print po.stdout.readline()
				print po.stdout.readline()
				print po.stdout.readline()
				print '----------------------------------------------'
				raise

			results.append(entry)
	except EOFError:
		pass

	ret = ( po.wait(), results )
	
	# Check the return value?
	if bCheckReturn and ret[0] != 0:
		print >>sys.stderr, "A command returned %d: %s" % (ret[0], cmd)
		sys.exit( 1 )

	return ( ret )
	


# Get the list of files. These are returned in a dictionary where the keys are the
# FixFilename'd filenames (lowercase and forward-slashes-only) and the values are 
# the non-lowercased version (which you need to send to Linux).
def GetP4OpenedFiles( perforceRoot, cmd ):
	if perforceRoot != None:
		perforceRoot = FixFilename( perforceRoot )
		
	(x,files) = ReadPerforceOutput( cmd, bCheckReturn=True )

	srcfiles = {}
	depotFiles = [ (x['depotFile'], x['action']) for x in files]
	for (perforceFilename,action) in depotFiles:
		# For now, just ignore delete commands. This means they won't get mirrored over 
		# to the remote end.
		if action == 'delete':
			continue
			
		fixed = FixFilename( perforceFilename )
		if len(fixed) == 0:
			break
		
		if perforceRoot == None or fixed.startswith( perforceRoot ):
			srcfiles[fixed] = perforceFilename
	
	return srcfiles


# Returns 'add', 'edit', 'remove', or 'none' (which either means nothing's happening to it or that depot file doesn't exist).
def GetClientFileAction( sDepotFilename ):
	kv = ReadPerforceOutput( 'p4 -G fstat \"%s\"' % sDepotFilename )[1][0]
	if kv.has_key( 'action' ):
		return kv[ 'action' ]
	else:
		return 'none'
	

# Returns ( client filename, perforce filename, action [edit/add/remove] )
def GetClientFileInfo( perforceFilename ):
	kv = ReadPerforceOutput( 'p4 -G fstat \"%s\"' % perforceFilename )[1][0]
	
	try:
		ret = [ kv['clientFile'], kv['depotFile'] ]
	except KeyError:
		print >>sys.stderr, "\nGetClientFileInfo( %s ) failed.\nPerhaps your clientspec doesn't include this file?" % perforceFilename
		sys.exit( 1 )
		
	if kv.has_key( 'action' ):
		ret.append( kv['action'] )
	else:
		ret.append( 'none' )
		
	return ret


# Returns a dictionary with info from p4 client.
# Particularly interesting are 'Root' (client's root folder), 'Client' (client name)
def GetClientInfo():
	return ReadPerforceOutput( 'p4 -G client -o' )[1][0]


# Scan the directory tree and get filenames relative to the specified dir.
def GetFilenamesRelativeTo_R( dirname ):
	ret = []
	
	for f in os.listdir( os.path.join(dirname) ):
		if f[0] == '.':
			continue
		
		fullname = os.path.join( dirname, f )
		s = os.stat( fullname )
		if stat.S_ISDIR( s[stat.ST_MODE] ):
			names = GetFilenamesRelativeTo_R( fullname )
			ret.extend( names )
		else:
			ret.append( fullname )
	
	return ret

def GetFilenamesRelativeTo( dirname ):
	ret = GetFilenamesRelativeTo_R( dirname )
	return [ x[len(dirname)+1:] for x in ret ]
	
	
def GetPendingChanges( p4client, fileFilter = "" ):
	cmd = 'p4 -G changes -s pending -c ' + p4client
	if ( len(fileFilter) > 0 ):
		cmd += ' ' + fileFilter
	return ReadPerforceOutput( cmd )[1]

def P4Where( file ):
	cmd = 'p4 -G where %s' % file
	return ReadPerforceOutput( cmd )[1][0][ "depotFile" ]

def GetSyncedRevision( p4ClientRoot ):
	cmd = 'p4 -G changes -s submitted -m 1 %s/...' % p4ClientRoot
	return ReadPerforceOutput( cmd )[1][0]['change']