#ifdef ENABLE_SUSEREPO

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "pool.h"
#include "repo.h"
#include "chksum.h"
#include "repo_content.h"
#include "repo_susetags.h"
#ifdef ENABLE_APPDATA
#include "repo_appdata.h"
#endif
#ifdef SUSE
#include "repo_autopattern.h"
#endif

#include "repoinfo.h"
#include "repoinfo_cache.h"
#include "repoinfo_download.h"
#include "repoinfo_type_susetags.h"

/* susetags helpers */

static const char *
susetags_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep)
{
  Pool *pool = repo->pool;
  Dataiterator di;
  const char *filename;

  filename = 0;
  *chksump = 0;
  *chksumtypep = 0;
  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, what, SEARCH_STRING);
  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
  if (dataiterator_step(&di))
    {
      dataiterator_setpos_parent(&di);
      *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, chksumtypep);
      filename = what;
    }
  dataiterator_free(&di);
  if (filename && !*chksumtypep)
    {
      printf("no %s file checksum!\n", what);
      filename = 0;
    }
  return filename;
}

static void
susetags_add_ext(Repo *repo, Repodata *data)
{
  Pool *pool = repo->pool;
  Dataiterator di;
  char ext[3];
  Id handle, filechksumtype;
  const unsigned char *filechksum;

  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, 0, 0);
  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
  while (dataiterator_step(&di))
    {
      if (strncmp(di.kv.str, "packages.", 9) != 0)
	continue;
      if (!strcmp(di.kv.str + 9, "gz"))
	continue;
      if (!di.kv.str[9] || !di.kv.str[10] || (di.kv.str[11] && di.kv.str[11] != '.'))
	continue;
      ext[0] = di.kv.str[9];
      ext[1] = di.kv.str[10];
      ext[2] = 0;
      if (!strcmp(ext, "en"))
	continue;
      if (!susetags_find(repo, di.kv.str, &filechksum, &filechksumtype))
	continue;
      handle = repodata_new_handle(data);
      repodata_set_str(data, handle, SUSETAGS_FILE_NAME, di.kv.str);
      if (filechksumtype)
	repodata_set_bin_checksum(data, handle, SUSETAGS_FILE_CHECKSUM, filechksumtype, filechksum);
      add_ext_keys(data, handle, ext);
      repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
    }
  dataiterator_free(&di);
}

int
susetags_load_ext(Repo *repo, Repodata *data)
{
  const char *filename, *descrdir;
  Id defvendor;
  char ext[3];
  FILE *fp;
  struct repoinfo *cinfo;
  const unsigned char *filechksum;
  Id filechksumtype;
  int flags;

  cinfo = repo->appdata;
  filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME);
  if (!filename)
    return 0;
  /* susetags load */
  ext[0] = filename[9];
  ext[1] = filename[10];
  ext[2] = 0;
  printf("[%s:%s", repo->name, ext);
  if (usecachedrepo(cinfo, ext, 0))
    {
      printf(" cached]\n"); fflush(stdout);
      return 1;
    }
  printf(" fetching]\n"); fflush(stdout);
  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
  if (!descrdir)
    descrdir = "suse/setup/descr";
  filechksumtype = 0;
  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype);
  if ((fp = curlfopen(cinfo, pool_tmpjoin(repo->pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 0)) == 0)
    return 0;
  flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
  if (strcmp(ext, "DL") != 0)
    flags |= REPO_LOCALPOOL;
  if (repo_add_susetags(repo, fp, defvendor, ext, flags))
    {
      fclose(fp);
      printf("%s\n", pool_errstr(repo->pool));
      return 0;
    }
  fclose(fp);
  writecachedrepo(cinfo, ext, data);
  return 1;
}

int
susetags_load(struct repoinfo *cinfo, Pool **sigpoolp)
{
  Repo *repo = cinfo->repo;
  Pool *pool = repo->pool;
  Repodata *data;
  const char *filename;
  const unsigned char *filechksum;
  Id filechksumtype;
  FILE *fp;
  const char *descrdir;
  int defvendor;

  printf("susetags repo '%s':", cinfo->alias);
  fflush(stdout);
  descrdir = 0;
  defvendor = 0;
  if ((fp = curlfopen(cinfo, "content", 0, 0, 0, 0)) == 0)
    {
      printf(" no content file\n");
      cinfo->incomplete = 1;
      return 0;
    }
  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
  cinfo->cookieset = 1;
  if (usecachedrepo(cinfo, 0, 1))
    {
      printf(" cached\n");
      fclose(fp);
      return 1;
    }
  if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "content.asc", sigpoolp))
    {
      fclose(fp);
      cinfo->incomplete = 1;
      return 0;
    }
  if (repo_add_content(repo, fp, 0))
    {
      printf("content: %s\n", pool_errstr(pool));
      fclose(fp);
      cinfo->incomplete = 1;
      return 0;
    }
  fclose(fp);
  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
  if (!descrdir)
    descrdir = "suse/setup/descr";
  filename = susetags_find(repo, "packages.gz", &filechksum, &filechksumtype);
  if (!filename)
    filename = susetags_find(repo, "packages", &filechksum, &filechksumtype);
  if (!filename)
    {
      printf(" no packages file entry, skipped\n");
      cinfo->incomplete = 1;
      return 0;
    }
  printf(" fetching\n");
  if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) == 0)
    {
      cinfo->incomplete = 1;
      return 0;	/* hopeless */
    }
  if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
    {
      printf("packages: %s\n", pool_errstr(pool));
      fclose(fp);
      cinfo->incomplete = 1;
      return 0;	/* hopeless */
    }
  fclose(fp);
  /* add default language */
  filename = susetags_find(repo, "packages.en.gz", &filechksum, &filechksumtype);
  if (!filename)
    filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype);
  if (filename)
    {
      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
	{
	  if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES))
	    {
	      printf("packages.en: %s\n", pool_errstr(pool));
	      cinfo->incomplete = 1;
	    }
	  fclose(fp);
	}
    }
  filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype);
  if (filename)
    {
      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
	{
	  char pbuf[256];
	  while (fgets(pbuf, sizeof(pbuf), fp))
	    {
	      int l = strlen(pbuf);
	      FILE *fp2;
	      if (l && pbuf[l - 1] == '\n')
		pbuf[--l] = 0;
	      if (!*pbuf || *pbuf == '.' || strchr(pbuf, '/') != 0)
		continue;
	      filename = susetags_find(repo, pbuf, &filechksum, &filechksumtype);
	      if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
		{
		  if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE))
		    {
		      printf("%s: %s\n", pbuf, pool_errstr(pool));
		      cinfo->incomplete = 1;
		    }
		  fclose(fp2);
		}
	    }
	  fclose(fp);
	}
    }
#ifdef ENABLE_APPDATA
  filename = susetags_find(repo, "appdata.xml.gz", &filechksum, &filechksumtype);
  if (!filename)
    filename = susetags_find(repo, "appdata.xml", &filechksum, &filechksumtype);
  if (filename && (fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
    {
      if (repo_add_appdata(repo, fp, 0))
	{
	  printf("appdata: %s\n", pool_errstr(pool));
	  cinfo->incomplete = 1;
	}
      fclose(fp);
    }
#endif
  repo_internalize(repo);
#ifdef SUSE
  repo_add_autopattern(repo, 0);
#endif
  data = repo_add_repodata(repo, 0);
  repodata_extend_block(data, repo->start, repo->end - repo->start);
  susetags_add_ext(repo, data);
  repodata_internalize(data);
  writecachedrepo(cinfo, 0, 0);
  repodata_create_stubs(repo_last_repodata(repo));
  return 1;
}

#endif
