// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016 Eduardo Aguiar
//
// 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, 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, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <mobius/application.h>
#include <mobius/io/file.h>
#include <mobius/io/folder.h>
#include <mobius/datetime/conv_iso_string.h>
#include <unistd.h>
#include <iostream>

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief show resource info
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
show_resource (const mobius::io::resource& r, int level = 0)
{
  const std::string indent (level * 2, ' ');

  if (!r || !r.exists ())
    {
      std::cout << indent << "? " << r.get_url () << std::endl;
      return;
    }

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // show metadata
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  std::cout << indent << (r.is_file () ? '.' : '+') << " " << r.get_url () << std::endl;
  std::cout << indent << "  size: " << r.get_size () << std::endl;
  std::cout << indent << "  user ID: " << r.get_user_id () << std::endl;
  std::cout << indent << "  user name: " << r.get_user_name () << std::endl;
  std::cout << indent << "  group ID: " << r.get_group_id () << std::endl;
  std::cout << indent << "  group name: " << r.get_group_name () << std::endl;
  std::cout << indent << "  permissions: " << std::oct << r.get_permissions () << std::dec << std::endl;
  std::cout << indent << "  last access time (atime): " << datetime_to_iso_string (r.get_last_access_time ()) << std::endl;
  std::cout << indent << "  last modification time (mtime): " << datetime_to_iso_string (r.get_last_modification_time ()) << std::endl;
  std::cout << indent << "  last metadata time (ctime): " << datetime_to_iso_string (r.get_last_metadata_time ()) << std::endl;

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // if resource is a file, show some bytes...
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  if (r.is_file ())
    {
      mobius::io::file f (r);

      try
        {
          auto reader = f.new_reader ();
          auto data = reader.read (16);

          std::cout << indent << "  first 16 bytes:";
          for (auto b : data)
            std::cout << ' ' << std::hex << int (b) << std::dec;
          std::cout << std::endl;
        }
      catch (const std::runtime_error& e)
        {
          if (errno != EACCES)
            throw;
        }
    }

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // if resource is a folder, recurse into folder
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  else
    {
      mobius::io::folder folder (r);

      try
        {
          for (auto child: folder)
            show_resource (child, level + 1);
        }
      catch (const std::runtime_error& e)
        {
          if (errno != EACCES)
            throw;
        }
    }
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief show usage text
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
usage ()
{
  std::cerr << std::endl;
  std::cerr << "use: dirtree [OPTIONS] <url1> [url2] ..." << std::endl;
  std::cerr << "e.g: dirtree file:///etc" << std::endl;
  std::cerr << std::endl;
  //std::cerr << "options are:" << std::endl;
  //std::cerr << "  -o offset\tstarting sector of the filesystem" << std::endl;
  //std::cerr << std::endl;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief main function
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int
main (int argc, char **argv)
{
  mobius::application& app = mobius::get_application ();
  std::cerr << app.name << " v" << app.version << " (dirtree v1.0)" << std::endl;
  std::cerr << "by Eduardo Aguiar" << std::endl;
  std::cerr << std::endl;

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // process command line
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  int opt;

  while ((opt = getopt (argc, argv, "")) != EOF)
    {
      /*if (opt == 'o')
        {
          offset = atol (optarg) * 512;
          break;
        }
      else
        {
          //std::cerr << "Error: Invalid option '-" << char (opt) << "'" << std::endl;
          usage ();
          exit (EXIT_FAILURE);
        }*/
    }

  if (optind == argc)
    {
      std::cerr << "Error: You must pass a valid URL to either a file or a folder" << std::endl;
      usage ();
      exit (EXIT_FAILURE);
    }

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // show resources
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  while (optind < argc)
    {
      mobius::io::resource r (argv[optind]);

      try
        {
          show_resource (r);
        }
      catch (const std::exception& e)
        {
          std::cerr <<  "Error: " << e.what () << std::endl;
          exit (EXIT_FAILURE);
        }

      optind++;
    }

  exit (EXIT_SUCCESS);
}
