/*
*  Naamari - an AES/SHA-based manual file crypto-synchronizer for cloud transfers
*  Copyright (c) 2015-2017 Sunkware
*  Key FP = 6B6D C8E9 3438 6E9C 3D97  56E5 2CE9 A476 99EF 28F6
*
*  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 3 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, see <http://www.gnu.org/licenses/>.
*
*  ----------------------------------------------------------------
*  WWW:       sunkware.org
*  E-mail:    sunkware@gmail.com
*  ----------------------------------------------------------------
*/

#include "ls.h"

using namespace cryptrav;

namespace commander
{


void           printFileStats(QDateTime time, qint64 size)
{
 Console::put("(", BRACKETCOLOR_DEFAULT);

 Console::put(TIMESS::strTime(time.toMSecsSinceEpoch() / 1000), TIMECOLOR_DEFAULT);
 Console::put("  " + QString::number(size, 10), SIZECOLOR_DEFAULT);
 Console::put(")", BRACKETCOLOR_DEFAULT);

 return;
}

QString       strAction(qint16 action)
{
 QString      actionStr;

 switch (action)
  {
   case ACTION_NONE: actionStr = ACTION_NONE_STRING; break;
   case ACTION_PUSH: actionStr = ACTION_PUSH_STRING; break;
   case ACTION_PULL: actionStr = ACTION_PULL_STRING; break;
   case ACTION_UNCLOUD: actionStr = ACTION_UNCLOUD_STRING; break;
   case ACTION_ANNIHILATE: actionStr = ACTION_ANNIHILATE_STRING; break; // useless, probably...
   default: actionStr = "UNKNOWN"; break;
  }

 return actionStr;
}

int            ls(ContextGlob* pContext, StateGlob* pState, QStringList argList)
{
 if ( (pContext == NULL) || (pState == NULL) )
  return COMERR_NULL_POINTER;


 QStringList comList;
 QStringList optList;
 CommandLineParser::separate(&argList, &comList, &optList);


 if ( optList.contains("--help") )
  {
   Console::putHelp("Available 'ls' subcommands:");
   Console::putHelp("  hallway  (alias: 'lsh')");
   Console::putHelp("  nominis  (alias: 'lsn')");
   Console::putHelp("Available 'ls' options:");
   Console::putHelp("  --help, --detail, --bytime, --bysize");
   Console::putHelp("'lshd' and 'lsnd' are aliases for 'lsh --detail' and 'lsn --detail'");

   return COMERR_OK;
  }


 QString       paramact = "";


 if (comList.count() < 1)
  {
   Console::putFailure("No subcommand (try 'ls --help')");
   return COMERR_NO_SUBCOMMAND;
  }

 paramact = comList.at(0);


 bool isDetail = optList.contains("--detail");


 int sortType = QDir::Name;
 if (optList.contains("--bytime")) sortType = QDir::Time;
 else if (optList.contains("--bysize")) sortType = QDir::Size;

 sortType |= QDir::DirsFirst;


 if (paramact == "hallway")
  {
   // This is one of only two places (for now; the other is at cryptrav/mover, in put())
   // where we explicitly require Hidden and System files/folders to be included into list.
   // (by default, they are not included, [.git] folder as an example)
   // These attributes are lost inside crypt.
   QFileInfoList entryInfoList = QDir( Pather(pContext).getHallwayAbs(pState -> getPathInHallway())).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::SortFlags(sortType));


   if (pState -> getPathInHallway() != "/")
    Console::putLine("..");

   for (int i = 0; i < entryInfoList.length(); i++)
    {
     QFileInfo fileInfo = entryInfoList.at(i);

     if ( fileInfo.isFile() )
      {
       Console::put("\"" + fileInfo.fileName() + "\"");

       if (isDetail)
        {
         Console::put("  ");
         printFileStats( fileInfo.lastModified(), fileInfo.size() );
        }

       Console::LF();

      }

     else
      {
       Console::put("[" + fileInfo.fileName() + "]");

       if (isDetail)
        Console::put("  " + TIMESS::strFileModTime(fileInfo.absoluteFilePath()), TIMECOLOR_DEFAULT);
         else
        Console::put("");

       Console::LF();
      }

    }

  }

 else if (paramact == "nominis")
  {
   CryptInfoList cryptInfoList = Lister(pContext, pState).entryCryptInfoList(pState -> getPathInNominis(), sortType);


   if (pState -> getPathInNominis() != "/")
    Console::putLine("..");

   for (int i = 0; i < cryptInfoList.length(); i++)
    {
     CryptInfo cryptInfo = cryptInfoList.at(i);

     if ( cryptInfo.isFile() )
      {
       Console::put("\"" + cryptInfo.fileName() + "\"");


       if (isDetail) // print state, time(s) & size(s), and action
        {

// print "near" file stats (if present)
         if (cryptInfo.isNear())
          {
           Console::put("  Near+ ", SUCCESSCOLOR_DEFAULT);
           printFileStats(cryptInfo.nearLastModified(), cryptInfo.nearSize());

          } else {
              Console::put("  Near-", FAILURECOLOR_DEFAULT);
             }

// print "far" file stats (if present)
         if (cryptInfo.isFar())
          {
           Console::put("  Far+ ", SUCCESSCOLOR_DEFAULT);
           printFileStats(cryptInfo.farLastModified(), cryptInfo.farSize());

          } else {
              Console::put("  Far-", FAILURECOLOR_DEFAULT);
             }

// mark it as "shade" if it's not near and far

         if ( (!cryptInfo.isNear()) && cryptInfo.isFar() ) {
           Console::put("  Shade", SHADECOLOR_DEFAULT);
          }

// print current action
         Console::put("  " + strAction(cryptInfo.action()), ACTIONCOLOR_DEFAULT);
        }

       Console::LF();
      }

     else // it's a dir
      {
       Console::put("[" + cryptInfo.fileName() + "]");

       if (isDetail)
        Console::put("  " + TIMESS::strTime(cryptInfo.lastModified().toMSecsSinceEpoch() / 1000), TIMECOLOR_DEFAULT);

       Console::LF();
      }

    }

  }

 else
  {
   Console::putFailure("Unknown subcommand (try 'ls --help')");
   return COMERR_UNKNOWN_SUBCOMMAND;
  }


 return COMERR_OK;
}


} // namespace "commander"
