#!/usr/bin/env python
### jack - extract audio from a CD and encode it using 3rd party software
### Copyright (C) 1999-2004  Arne Zellentin <zarne@users.sf.net>

### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.

### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.

### You should have received a copy of the GNU General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

### If you want to comment on this program, contact me: zarne@users.sf.net ###
### Visit the homepage: http://www.home.unix-ag.org/arne/jack/

### see CHANGELOG for recent changes in this program
### see TODO if you want to see what needs to be implemented

import os
import sys
import time
import wave
import types
import posix
import string
import select
import signal
import pprint
import traceback

from jack_globals import *

import jack_version
import jack_misc
import jack_mp3
import jack_argv
import jack_rc
import jack_helpers
import jack_targets
import jack_freedb
import jack_display
import jack_term
import jack_children
import jack_tag
import jack_workers
import jack_utils
import jack_ripstuff
import jack_encstuff
import jack_checkopts
import jack_status
import jack_functions
import jack_main_loop
import jack_progress
import jack_prepare


##############################################################################
###################### M A I N ###############################################
##############################################################################

# say hello...
print "This is", jack_version.prog_name, jack_version.prog_version, jack_version.prog_copyright, jack_version.prog_devemail

### interpret options
global_cf = jack_rc.load(cf, cf['global_rc']['val'])
jack_checkopts.checkopts(cf, global_cf)
cf.rupdate(global_cf, "global_rc")
user_cf = jack_rc.load(cf, cf['user_rc']['val'])
jack_checkopts.checkopts(cf, user_cf)
cf.rupdate(user_cf, "user_rc")
help, argv_cf = jack_argv.parse_argv(cf, sys.argv)
jack_checkopts.checkopts(cf, argv_cf)
cf.rupdate(argv_cf, "argv")
if help:
    jack_argv.show_usage(cf, long=help-1)
    sys.exit(0)
debug("global_cf: " + `global_cf`)
debug("user_cf: " + `user_cf`)
debug("argv_cf: " + `argv_cf`)

jack_checkopts.consistency_check(cf)

if cf['save_args']['val'] == 1:
    count = jack_rc.save(cf['user_rc']['val'], cf)
    info("%d options saved in %s" % (count, cf['user_rc']['val']))
    sys.exit()

ext = jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension']

### (1) search for a dir containing a toc-file or do the multi-mode
toc_just_read = jack_prepare.find_workdir()
os.environ["JACK_CUR_DIR"] = os.getcwd()
os.environ["JACK_BASE_DIR"] = cf['_base_dir']
# now we are set to go as we know we are in the right dir

### (2) check toc (operation mode)
if cf['_check_toc']:
    jack_prepare.check_toc()
    sys.exit(0)

### (3a) read and interpret toc_file
is_submittable, track1_offset = jack_prepare.read_toc_file()

### (3b) make sure we have a freedb file
if not os.path.exists(cf['_freedb_form_file']):
    jack_freedb.freedb_template(jack_ripstuff.all_tracks)

### (4a) filter out data tracks
jack_prepare.filter_tracks(toc_just_read)

### (4b) Parse tracks from argv, generate todo
todo = jack_prepare.gen_todo()
if len(todo) == 0:
    error("nothing to do. bye.")

### init status
jack_status.init(todo)

#XXX## (5) read progress info into status

jack_ripstuff.all_tracks_orig = []
for i in jack_ripstuff.all_tracks:
    jack_ripstuff.all_tracks_orig.append(i[:])

status = jack_prepare.init_status()

### (6) update progress file at user's request (operation mode)
if cf['_upd_progress']:
    jack_prepare.update_progress(todo)
    sys.exit(0)

### (7) now read in the progress file
status = jack_prepare.read_progress(status, todo)

### (8) submit freedb data on user's request
if cf['_freedb_submit'] or cf['_freedb_mailsubmit']:
    jack_prepare.freedb_submit()
    sys.exit(0)

### (9) do query on start
freedb_rename = 0
if cf['_query_if_needed']:
    if not os.path.exists(cf['_freedb_form_file'] + ".bak"):
        cf['_query_on_start'] = 1
if cf['_query_on_start']:
    freedb_rename = jack_prepare.query_on_start()

### (10) update freedb dbfile
if cf['_update_freedb']:
    if not jack_tag.track_names:
        err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 0)
    jack_freedb.freedb_template(jack_ripstuff.all_tracks, jack_tag.track_names, revision + 1)
    jack_utils.ex_edit(cf['_freedb_form_file'])
    info("now submit your changes if you like, using the option --submit (via http POST). Don't forget to activate your changes locally with -R")
    sys.exit(0)

### (11) undo renaming (operation mode)
if cf['_undo_rename']:
    jack_prepare.undo_rename(status, todo)
    sys.exit(0)

#### Reorder if told so
if cf['_reorder']:
    todo.sort(jack_utils.cmp_toc)
    todo.reverse()

#### check how much bytes we can burn
if cf['space_from_argv']['history'][-1][0] == "argv":
    space = jack_ripstuff.raw_space = cf['_space_from_argv']
else:
    space = jack_ripstuff.raw_space = jack_functions.df()

#### check what is already there
space, remove_q, wavs_todo, mp3s_todo, dae_queue, enc_queue = jack_prepare.what_todo(space, todo)

if cf['_todo_exit']:           # print what needs to be done, then exit
    jack_prepare.print_todo(todo, wavs_todo, mp3s_todo)
    sys.exit(0)

# now mp3s_todo contains the tracks where the wavs only need to be coded and
# wavs_todo lists those tracks which need to be dae'd end enc'd. The dae_queue
# has been filled from wavs_todo (todo is superflous now). The main_loop
# will handle the tracks in mp3s_todo.

### make sure we have enough space to rip the whole thing
jack_prepare.check_space(space, wavs_todo, mp3s_todo)

cf['_max_load'] = cf['_max_load'] + cf['_encoders'] #XXX

if not cf['_dont_work'] and dae_queue:     # check if inserted cd matches toc.
    jack_prepare.check_cd() # why? paranoia or needed? XXX
    if cf['_rip_from_device']:
        all_tracks_on_cd = jack_functions.gettoc(cf['_toc_prog'])
        if not cf['_force'] and not jack_utils.cmp_toc_cd(jack_ripstuff.all_tracks_orig, all_tracks_on_cd, what=(NUM, LEN)):
            error("you did not insert the right cd")

### if we have work to do, we may have to remove some files first
if remove_q:
    jack_prepare.remove_files(remove_q)

### bail out now if told so
if cf['_dont_work']:
    info("quitting now as requested.")
    sys.exit(0)

### install signal handlers
signal.signal(signal.SIGTERM, jack_display.sig_handler)
signal.signal(signal.SIGINT, jack_display.sig_handler)
signal.signal(signal.SIGQUIT, jack_display.sig_handler)
signal.signal(signal.SIGHUP, jack_display.sig_handler)


       #\                         /#
#########> real work starts here <#############################################
       #/                         \#

global_error = None
if (wavs_todo or mp3s_todo):
    jack_ripstuff.gen_printable_names(jack_tag.track_names, todo)
    jack_term.init(cf['_terminal'], cf['_xtermset_enable'])
    jack_display.init()
    try:
        jack_term.enable()
        global_error = jack_main_loop.main_loop(mp3s_todo, wavs_todo, space, dae_queue, enc_queue, track1_offset)
    except SystemExit:
        jack_term.disable()
        print jack_display.options_string
        print "--- Last status: ---------------------------------------------------------------"
        jack_status.print_status(form = 'short')
        sys.exit(0)
    except:
        jack_term.disable()
        warning("abnormal exit")
        traceback.print_exc()         
        sys.exit(1)
# Set the files we have processed but this may still be overwritten by
# jack_tag.tag() called below.
os.environ["JACK_JUST_ENCODED"] = "\n".join([x[NAME] + ext for x in mp3s_todo])
os.environ["JACK_JUST_RIPPED"] = "\n".join([x[NAME] + ".wav" for x in wavs_todo])

jack_term.disable()
if cf['_query_when_ready']:
    info("querying...")
    if jack_freedb.freedb_query(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, cf['_freedb_form_file']):
        jack_display.exit()

if cf['_query_when_ready'] or cf['_read_freedb_file'] or cf['_query_on_start']:
    err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 1)
    if err:
        error("could not read freedb file")

if jack_term.term_type == "curses":
    if jack_display.options_string:
        print jack_display.options_string
    print "The final status was:"
    jack_status.print_status(form = 'short')

if global_error:
    if cf['_exec_when_done']:
        os.system(cf['_exec_err'])
    error("aborting because of previous error(s) [%i]." % global_error)

jack_tag.tag(freedb_rename)

if jack_functions.progress_changed:
    jack_functions.progress("all", "done", time.strftime("%b %2d %H:%M:%S", time.localtime(time.time())))

if cf['_remove_files']:
    print "cleaning up in", os.getcwd()
    for i in [cf['_progress_file'], cf['_toc_file'], cf['_def_toc'], cf['_freedb_form_file'], cf['_freedb_form_file'] + ".bak"]:
        if os.path.exists(i):
            os.remove(i)

if cf['_exec_when_done']:
    os.system(cf['_exec_no_err'])

jack_display.exit()      # call the cleanup function & exit


###############################################################################
##################################         ####################################
##################################  T H E  ####################################
##################################  E N D  ####################################
##################################         ####################################
###############################################################################
