#!/bin/bash
# License: lgpl v2

main(){
  public_name="Turtle Kevux System Extractor"
  system_name=extract_system
  version=0.3.1

  local source_path=
  local destination_path=
  local method=all
  local i=
  local exclude=
  local live_path=boot/live/
  local live=normal

  while [[ $count -lt $main_size ]] ; do
    i=${main_input[$count]}

    if [[ $grab_next == "" ]] ; then
      if [[ $i == "-h" || $i == "--help" ]] ; then
        do_help=yes
        break
      elif [[ $i == "+n" || $i == "++no_color" ]] ; then
        do_color=none
      elif [[ $i == "+l" || $i == "++light" ]] ; then
        do_color=light
      elif [[ $i == "+v" || $i == "++version" ]] ; then
        echo $version
        return
      elif [[ $i == "-s" || $i == "--source" ]] ; then
        grab_next="source"
      elif [[ $i == "-d" || $i == "--destination" ]] ; then
        grab_next="destination"
      elif [[ $i == "-m" || $i == "--method" ]] ; then
        grab_next="method"
      elif [[ $i == "-e" || $i == "--exclude" ]] ; then
        grab_next="exclude"
      elif [[ $i == "-p" || $i == "--live_path" ]] ; then
        grab_next="live_path"
      elif [[ $i == "-n" || $i == "--no_live" ]] ; then
        live=none
      elif [[ $i == "-o" || $i == "--only_live" ]] ; then
        live=only
      fi
    else
      if [[ $grab_next == "source" ]] ; then
        source_path=$i
      elif [[ $grab_next == "destination" ]] ; then
        destination_path=$i
      elif [[ $grab_next == "method" ]] ; then
        method=$i
      elif [[ $grab_next == "exclude" ]] ; then
        exclude="$exclude$i "
      elif [[ $grab_next == "live_path" ]] ; then
        live_path=$(echo $i | sed -e 's|^/*||' -e 's|/*$|/|')
      fi

      grab_next=
    fi

    let count=$count+1
  done

  standard_handle_colors

  if [[ $do_help != "" ]] ; then
    show_help
    return
  fi

  if [[ $source_path == "" ]] ; then
    standard_error "No source path was specified"
    cleanup_main
    exit -1;
  fi

  extract_system
}

show_help(){
  standard_help_title
  echo -e "$c_highlight$system_name$c_reset $c_notice[${c_reset}options$c_notice]$c_reset"
  echo -e " This is will extract a compressed kevux system to a specified directory"
  echo
  standard_help_options
  echo -e " -${c_important}s${c_reset}, --${c_important}source${c_reset}      The mounted cd-rom device path"
  echo -e " -${c_important}d${c_reset}, --${c_important}destination${c_reset} The location where the system will be extracted"
  echo -e " -${c_important}m${c_reset}, --${c_important}method${c_reset}      How to extract: all, core, minimal"
  echo -e " -${c_important}e${c_reset}, --${c_important}exclude${c_reset}     Directories to exclude from extracting and copying"
  echo -e " -${c_important}p${c_reset}, --${c_important}live_path${c_reset}   Path where squash files are copied (default: boot/live/)"
  echo -e " -${c_important}n${c_reset}, --${c_important}no_live${c_reset}     Do not copy squash files to live_path"
  echo -e " -${c_important}o${c_reset}, --${c_important}only_live${c_reset}   Only copy squash files to live_path"
  echo
}

enforce_permission(){
  if [[ $1 == "bin" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw bin
    chgrp d_program bin
    chmod g-s bin
  elif [[ $1 == "boot" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw boot
    chgrp d_boot boot
  elif [[ $1 == "dev" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw dev
    chgrp d_device dev
    chmod g-s dev
  elif [[ $1 == "documentation" ]] ; then
    chmod u+rwx,g+rxs-w,o-rwx documentation
    chgrp d_documentation documentation
  elif [[ $1 == "etc" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw etc
    chgrp d_setting etc
  elif [[ $1 == "home" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw home
    chgrp d_home home
  elif [[ $1 == "lib" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw lib
    chgrp d_library lib
    chmod g-s lib
  elif [[ $1 == "mnt" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw mnt
    chgrp d_mount mnt
  elif [[ $1 == "proc" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw proc
    chgrp k_process proc
    chmod g-s proc
  elif [[ $1 == "sys" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw sys
    chgrp k_system sys
    chmod g-s sys
  elif [[ $1 == "sbin" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw sbin
    chgrp d_program_system sbin
    chmod g-s sbin
  elif [[ $1 == "share" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw share
    chgrp d_data share
  elif [[ $1 == "tmp" ]] ; then
    chmod u+rwx,g+rxw,o-rwx tmp
    chmod +t tmp
    chgrp d_temporary tmp
    chmod g-s tmp
  elif [[ $1 == "toolchain" ]] ; then
    chmod u+rwx,g+rxs-w,o-rwx toolchain
    chgrp d_toolchain toolchain
  elif [[ $1 == "var" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw var
    chgrp d_variable var
  elif [[ $1 == "modules" ]] ; then
    chmod u+rwx,g+rxs-w,o-rwx modules
    chgrp d_module modules
  elif [[ $1 == "firmware" ]] ; then
    chmod u+rwx,g+rxs-w,o-rwx firmware
    chgrp d_module firmware
  elif [[ $1 == "checksum" ]] ; then
    chmod u+rwx,g+rxs-w,o-rwx checksum
    chgrp d_checksum checksum
  elif [[ $1 == "package" ]] ; then
    chmod u+rwx,g+rxs-w,o+x-rw package
    chgrp d_package package
  elif [[ $1 == "python" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw python
    chgrp d_python python
    chmod g-s python
  elif [[ $1 == "perl" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw perl
    chgrp d_perl perl
    chmod g-s perl
  fi
}

extract_system(){
  local copy_files=
  local make_directories=
  local extract_directories=
  local i=

  if [[ $(echo $source_path | grep -s "/$") == "" ]] ; then
    source_path=${source_path}/
  fi

  # guess at the location of the files
  if [[ ! -f ${source_path}bin.sfs ]] ; then
   if [[ -f ${source_path}live/bin.sfs ]] ; then
     source_path=${source_path}live/
   elif [[ -f ${source_path}boot/live/bin.sfs ]] ; then
     source_path=${source_path}boot/live/
   fi
  fi

  if [[ ! -f ${source_path}bin.sfs ]] ; then
    standard_error "Unable to find the squash files (namely: $c_notice${source_path}bin.sfs$c_error)"
    cleanup_main
    exit -1;
  fi

  if [[ $destination_path != "" ]] ; then
    if [[ ! -d $destination_path ]] ; then
      error_on_extract "The destination path '$destination_path' is not a valid directory."
    fi

    pushd $destination_path &>/dev/null

    if [[ $? -ne 0 ]] ; then
      error_on_extract "Failed to change directory to destination path: '$destination_path'." "pop"
    fi
  fi

  if [[ $method == "minimal" ]] ; then
    copy_files="dev documentation etc home var checksum bin lib sbin share toolchain firmware package perl python"
    make_directories="dev documentation etc home var checksum bin lib sbin share toolchain proc sys tmp mnt modules firmware"
    extract_directories="boot"
  elif [[ $method == "core" ]] ; then
    copy_files="bin lib sbin share toolchain firmware"
    make_directories="bin lib sbin share toolchain proc sys tmp mnt modules firmware package perl python"
    extract_directories="boot dev documentation etc home var checksum"
  elif [[ $method == "all" ]] ; then
    make_directories="proc sys tmp mnt modules"
    extract_directories="boot dev documentation etc home var checksum bin lib sbin share toolchain firmware package perl python"
  else
    standard_error "invalid method name '$c_notice$method$c_error', must be one of: all, core, or minimal"
    cleanup_main
    exit -1;
  fi

  if [[ $live == "none" ]] ; then
    copy_files=
  elif [[ $live == "only" ]] ; then
    make_directories=
    extract_directories=
  fi

  for i in $extract_directories; do
    if [[ $(echo $exclude | grep -s -o "\<$i\>") != "" ]] ; then
      continue
    fi

    if [[ -e ${source_path}$i.sfs ]] ; then
      echo -e "${c_title}Now Extracting:$c_notice $i$c_reset"

      unsquashfs -n ${source_path}$i.sfs ||
      error_on_extract $i "pop"

      if [[ -d $i ]] ; then
        mv squashfs-root/* $i &&
        rmdir squashfs-root &&
        enforce_permission $i ||
        error_on_extract $i "pop"
      else
        mv -v squashfs-root $i ||
        error_on_extract $i "pop"
      fi
    else
      standard_warning "Skipping: '$c_notice$i$c_warning', could not find the file: $c_notice${source_path}$i.sfs"
    fi
  done

  for i in $make_directories; do
    if [[ $(echo $exclude | grep -s -o "\<$i\>") != "" ]] ; then
      continue
    fi

    echo -e "${c_title}Now Creating Directory:$c_notice $i$c_reset"

    mkdir -p $i &&
    enforce_permission $i ||
    error_on_mkdir $i "pop"
  done

  if [[ ! -d $live_path && $live != "none" ]] ; then
    mkdir -p $live_path
    chmod u+rwx,g+rx-w,o-rw+x $live_path
    chgrp d_boot $live_path
    chmod g+s $live_path
  fi

  for i in $copy_files; do
    if [[ $(echo $exclude | grep -s -o "\<$i\>") != "" ]] ; then
      continue
    fi

    echo -e "${c_title}Now Copying Compressed File:$c_notice $i$c_reset"

    if [[ -f $source_path$i.sfs ]] ; then
      cp --progress $source_path$i.sfs $live_path ||
      error_on_copy $source_path$i "pop"
      chmod oug-x $live_path$i.sfs
    else
      # show an error message for missing required files
      if [[ $i != "toolchain" && $i != "documentation" && $i != "checksum" ]] ; then
        error_no_file $source_path$i "pop"
      else
        echo -e "${c_warning}Not copying:$c_notice $i$c_warning, it was not found, cannot be read, or is not a file; however, it is not required$c_reset"
      fi
    fi
  done

  if [[ $(echo $exclude | grep -s -o "\<kernel_modules\>") == "" ]] ; then
    for i in $(find ${source_path} -name '*.modules') ; do
      local j=$(echo $i | sed -e "s|^${source_path}||" -e "s|.modules$||")

      if [[ -f $i ]] ; then
        if [[ $method == "all" && $live != "only" ]] ; then
          echo -e "${c_title}Now Extracting:$c_notice $j$c_reset"
          unsquashfs -n $i &&
          mv -v squashfs-root modules/$j ||
          error_on_extract $i "pop"
        elif [[ $live != "none" ]] ; then
          echo -e "${c_title}Now Copying Compressed File:$c_notice $j$c_reset"
          cp --progress $i $live_path ||
          error_on_copy $i "pop"
        fi
      else
        error_no_file $i "pop"
      fi
    done
  fi

  if [[ $destination_path != "" ]] ; then
    popd &>/dev/null
  fi

  # set the appropriate root directory permissions
  if [[ $destination_path != "" ]] ; then
    chmod u+rwx,g+rx-w,o+x-rw $destination_path
    chgrp d_root $destination_path
  else
    chmod u+rwx,g+rx-w,o+x-rw .
    chgrp d_root .
  fi
}

error_on_extract(){
  if [[ $2 != "" ]] ; then
    popd &>/dev/null
  fi

  standard_error "Failed to extract '$c_notice$1$c_error', stopping here"
  cleanup_main
  exit -1
}

error_on_mkdir(){
  if [[ $2 != "" ]] ; then
    popd &>/dev/null
  fi

  standard_error "Failed to create directory '$c_notice$1$c_error', stopping here"
  cleanup_main
  exit -1
}

error_on_copy(){
  if [[ $2 != "" ]] ; then
    popd &>/dev/null
  fi

  standard_error "Failed to copy file '$c_notice$1$c_error', stopping here"
  cleanup_main
  exit -1
}

error_no_file(){
  if [[ $2 != "" ]] ; then
    popd &>/dev/null
  fi

  standard_error "The file '$c_notice$1$c_error' either does not exist, cannot be read, or is not a file"
  cleanup_main
  exit -1
}

cleanup_main(){
  standard_unset

  unset error_no_file
  unset error_on_copy
  unset error_on_mkdir
  unset error_on_extract
  unset extract_system
  unset enforce_permission
  unset show_help
  unset main
  unset cleanup_main
}

OLD_PATH=$PATH
PATH=/tkis/tools/lib/scripts/turtle_kevux/:$PATH
source $(type -p turtle_kevux_scripts-standard)
PATH=$OLD_PATH
unset OLD_PATH

# populate main_input variable
main_input=
main_size=$#
c1=0
c2=

while [[ $c1 -lt $main_size ]] ; do
  let c2=$c1+1
  main_input[$c1]=${!c2}
  let c1=$c1+1
done

unset c1 c2

# execute the program
standard_main_execute=main
standard_main
cleanup_main
unset main_input main_size
