#include <config.h>

#include <apt-pkg/cachefile.h>
#include <apt-pkg/cmndline.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/hashes.h>
#include <apt-pkg/sourcelist.h>
#include <apt-pkg/strutl.h>

#include <apt-private/private-output.h>
#include <apt-private/private-sources.h>
#include <apt-private/private-utils.h>

#include <iostream>
#include <string>
#include <stddef.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <apti18n.h>

/* Interface discussion with donkult (for the future):
  apt [add-{archive,release,component}|edit|change-release|disable]-sources
 and be clever and work out stuff from the Release file
*/

// EditSource - EditSourcesList						/*{{{*/
class APT_HIDDEN ScopedGetLock {
public:
   int fd;
   explicit ScopedGetLock(std::string const &filename) : fd(GetLock(filename)) {}
   ~ScopedGetLock() { close(fd); }
};
bool EditSources(CommandLine &CmdL)
{
   std::string sourceslist;
   if (CmdL.FileList[1] != NULL)
   {
      sourceslist = _config->FindDir("Dir::Etc::sourceparts") + CmdL.FileList[1];
      if (!APT::String::Endswith(sourceslist, ".list"))
         sourceslist += ".list";
   } else {
      sourceslist = _config->FindFile("Dir::Etc::sourcelist");
   }
   HashString before;
   if (FileExists(sourceslist))
       before.FromFile(sourceslist);
   else
   {
      FileFd filefd;
      if (filefd.Open(sourceslist, FileFd::Create | FileFd::WriteOnly, FileFd::None, 0644) == false)
	 return false;
   }

   ScopedGetLock lock(sourceslist);
   if (lock.fd < 0)
      return false;

   bool res;
   bool file_changed = false;
   do {
      if (EditFileInSensibleEditor(sourceslist) == false)
	 return false;
      if (before.empty())
      {
	 struct stat St;
	 if (stat(sourceslist.c_str(), &St) == 0 && St.st_size == 0)
	       RemoveFile("edit-sources", sourceslist);
      }
      else if (FileExists(sourceslist) && !before.VerifyFile(sourceslist))
      {
	 file_changed = true;
	 pkgCacheFile::RemoveCaches();
      }
      pkgCacheFile CacheFile;
      res = CacheFile.BuildCaches(nullptr);
      if (res == false || _error->empty(GlobalError::WARNING) == false) {
	 std::string outs;
	 strprintf(outs, _("Failed to parse %s. Edit again? "), sourceslist.c_str());
         // FIXME: should we add a "restore previous" option here?
         if (YnPrompt(outs.c_str(), true) == false)
	 {
	    if (res == false && _error->PendingError() == false)
	    {
	       CacheFile.Close();
	       pkgCacheFile::RemoveCaches();
	       res = CacheFile.BuildCaches(nullptr);
	    }
	    break;
	 }
      }
   } while (res == false);

   if (res == true && file_changed == true)
   {
      ioprintf(
         std::cout, _("Your '%s' file changed, please run 'apt-get update'.\n"),
         sourceslist.c_str());
   }
   return res;
}
									/*}}}*/
