#!/usr/bin/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 signal
import traceback
import locale

from jack.globals import *

import jack.version
import jack.argv
import jack.rc
import jack.helpers
import jack.targets
import jack.metadata
import jack.display
import jack.term
import jack.tag
import jack.utils
import jack.ripstuff
import jack.checkopts
import jack.status
import jack.functions
import jack.main_loop
import jack.prepare
import jack.generic


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

def main():
    locale.setlocale(locale.LC_ALL, "")

    ### 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_verbosity, argv_cf, searches = jack.argv.parse_argv(cf, sys.argv)
    jack.checkopts.checkopts(cf, argv_cf)
    cf.rupdate(argv_cf, "argv")

    # say hello...
    jack.generic.indent("", f"This is {jack.version.name} "
            f"{jack.version.version} "
            f"{jack.version.copyright}. "
            f"{jack.version.url}", show=True)

    if help_verbosity:
        jack.argv.show_usage(cf, help_verbosity, searches)
        sys.exit(0)
    debug("global_cf: " + repr(global_cf))
    debug("user_cf: " + repr(user_cf))
    debug("argv_cf: " + repr(argv_cf))

    jack.checkopts.check_rc(cf, global_cf, user_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 new options saved in %s" % (count, cf['user_rc']['val'][0]))
        sys.exit()

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

    ### 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

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

    ### read and interpret toc_file
    track1_offset = jack.prepare.read_toc_file()

    ### make sure we have a metadata file
    metadata_form_file = jack.metadata.get_metadata_form_file(jack.metadata.get_metadata_api(cf['_metadata_server']))
    if not os.path.exists(metadata_form_file):
        jack.metadata.metadata_template(jack.ripstuff.all_tracks)

    ### init status
    jack.status.init(jack.ripstuff.all_tracks)

    #XXX## 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()

    jack.prepare.tracknum = {}
    for i in jack.ripstuff.all_tracks:
        jack.prepare.tracknum[i[NUM]] = i

    ### now read in the progress file
    status = jack.prepare.read_progress(status, jack.ripstuff.all_tracks)

    ### filter out data tracks
    jack.prepare.filter_tracks(toc_just_read, status)

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

    ### Lookup the CD on MusicBrainz
    if cf['_metadata_lookup']:
        jack.prepare.metadata_lookup()
        sys.exit(0)

    ### do query on start
    metadata_rename = 0
    if cf['_query_if_needed']:
        if not os.path.exists(metadata_form_file + ".bak"):
            cf['_query_on_start'] = 1
            cf['_set_tag'] = 1
    if cf['_query_on_start']:
        metadata_rename = jack.prepare.query_on_start(todo)

    ### update metadata dbfile
    if cf['_update_metadata']:
        if not jack.tag.track_names:
            err, jack.tag.track_names, metadata_rename, jack.tag.mb_query_data = jack.metadata.interpret_db_file(jack.ripstuff.all_tracks, todo, metadata_form_file, verb = 1, dirs = 0)
        jack.metadata.metadata_template(jack.ripstuff.all_tracks, jack.tag.track_names)
        jack.utils.ex_edit(metadata_form_file)
        info("Don't forget to activate your changes locally with -R")
        sys.exit(0)

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

    ### 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, trc_tracks = 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, trc_tracks)
        except SystemExit:
            jack.term.disable()
            print(jack.display.options_string)
            print("--- Last status: ---------------------------------------------------------------")
            jack.status.print_status(form = 'short')
            sys.exit(0)
        except Exception:
            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.metadata.metadata_query(jack.metadata.metadata_id(jack.ripstuff.all_tracks), jack.ripstuff.all_tracks, metadata_form_file):
            jack.display.exit()

    if cf['_query_when_ready'] or cf['_read_metadata_file'] or cf['_query_on_start']:
        err, jack.tag.track_names, metadata_rename, jack.tag.mb_query_data = jack.metadata.interpret_db_file(jack.ripstuff.all_tracks, todo, metadata_form_file, verb = 1, dirs = 1)
        if err:
            error("could not read metadata 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(metadata_rename)

    if jack.functions.progress_changed:
        jack.functions.progress("all", "done", str(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'], metadata_form_file, metadata_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

if __name__ == "__main__":
    sys.exit(main())


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