#!/usr/bin/env python
#
# Replacement for old mkbundle script that creates a full file heirarchy
#

import os, sys, re
import gzip, cStringIO
from optparse import OptionParser

# Add reverse path split
def rsplit ( p ):
  i = p.find(os.path.sep)
  if i != -1:
    return (p[:i], p[i+1:])
  else:
    return (p, '')

# Process command line
optp = OptionParser()
optp.add_option('-z', '--gzip', action='store_true',
                help='Compress the files with gzip')
optp.add_option('-l', '--gzlevel', type='int', default=9,
                help='Specify compression level if using gzip')
optp.add_option('-o', '--output', default=None,
                help='Specify output file (default /dev/stdout)')
optp.add_option('-d', '--deps', default=None,
                help='Specify deps file to update during run')
(opts, args) = optp.parse_args()

# Setup
outf = sys.stdout
if opts.output:
  outf = open(opts.output, 'w')
depf = None
if opts.deps:
  depf = open(opts.deps, 'w')
  print >>depf, '%s: \\' % opts.output

# Build heirarchy
root  = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
ents  = {}
for path in args:
  for (p, ds, fs) in os.walk(path):
    p = os.path.abspath(p)
    n = p.replace(root+'/', '')
    t = ents
    while True:
      (d,n) = rsplit(n)
      if d.startswith('.'):
        fs = []
        break
      if d not in t:
        t[d] = {}
      t = t[d]
      if not n: break
    for f in fs:
      if f.startswith('.'): continue
      t[f] = None

# Output a file
def output_file ( path, name, idx, next = -1 ):
  n = 'NULL'
  if next >= 0: n = '&filebundle_entry_%06d' % next
  p = os.path.join(root, path, name);

  # Dep file
  if depf: print >>depf, '  %s\\' % p

  # First the data
  print >>outf, '// FILE : %s %s %d %d' % (path, name, idx, next)
  print >>outf, 'static const uint8_t filebundle_data_%06d[] = {' % idx,
  o = -1
  d = open(p, 'rb').read()
  if opts.gzip:
    o = len(d)
    l = opts.gzlevel
    t = cStringIO.StringIO()
    if l < 0: l = 1
    if l > 9: l = 9
    z = gzip.GzipFile(filename=name, mode='w', compresslevel=l, fileobj=t)
    z.write(d)
    z.close()
    d = t.getvalue()
    t.close()
  i = 0
  for b in d:
    if not (i % 12): print >>outf, '\n  ',
    print >>outf, '0x%02x,' % ord(b),
    i = i + 1
  print >>outf, ''
  print >>outf, '};'
  
  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
  print >>outf, '  .type    = FB_FILE,'
  print >>outf, '  .name    = "%s",'  % name
  print >>outf, '  .next    = %s,' % n
  print >>outf, '  {'
  print >>outf, '    .f.size  = %d,' % len(d)
  print >>outf, '    .f.orig  = %d,' % o
  print >>outf, '    .f.data  = filebundle_data_%06d' % idx
  print >>outf, '  },'
  print >>outf, '};'
  print >>outf, ''

# Output a directory
def output_dir ( path, name, idx, child, count, next = -1 ):
  n = 'NULL'
  if next >= 0: n = '&filebundle_entry_%06d' % next
  print >>outf, '// DIR: %s %s %d %d %d %d'\
  % (path, name, idx, child, count, next)
  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
  print >>outf, '  .type    = FB_DIR,'
  print >>outf, '  .name    = "%s",'  % name
  print >>outf, '  .next    = %s,' % n
  print >>outf, '  {'
  print >>outf, '    .d.count = %d,' % count
  print >>outf, '    .d.child = &filebundle_entry_%06d' % child
  print >>outf, '  },'
  print >>outf, '};'
  print >>outf, ''

# Create output
def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):

  # Add children
  d = os.path.join(path, name)
  p = -1
  c = 0
  for k in ents:
    
    # File
    if ents[k] is None:
      output_file(d, k, idx+1, p)
      p = idx = idx + 1
      c = c + 1
      
    # Directory
    else:
      tmp = add_entry(ents[k], d, k, idx, p)
      if tmp != idx:
        p = idx = tmp
        c = c + 1

  # Add directory
  if p >= 0:
    if name:
      output_dir(path, name, idx+1, p, c, next)
      idx = idx + 1

  return idx

# Output header
print >>outf, '// Auto-generated - DO NOT EDIT'
print >>outf, '// COMMAND: [%s]' % (' '.join(sys.argv))
print >>outf, ''
print >>outf, '#include "filebundle.h"'
print >>outf, ''

# Output entries
idx = add_entry(ents)

# Output top link
print >>outf, 'filebundle_entry_t *filebundle_root = &filebundle_entry_%06d;'  % idx