/*****************************************************************
 * gmerlin - a general purpose multimedia framework and applications
 *
 * Copyright (c) 2001 - 2012 Members of the Gmerlin project
 * gmerlin-general@lists.sourceforge.net
 * http://gmerlin.sourceforge.net
 *
 * 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 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/>.
 * *****************************************************************/

#include <config.h>
#include <gmerlin/utils.h>
#include <gmerlin/log.h>
#include <gmerlin/translation.h>
#include <gmerlin/cfgctx.h>
#include <gmerlin/cmdline.h>

#include "db2nmj.h"



#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>

#define LOG_DOMAIN "gmerlin-db2nmj"

char * path = ".";

#define ROOT_DIR_SIZE 2048
char root_dir[ROOT_DIR_SIZE];
int root_dir_len = 0;

bg_db_t * db;
sqlite3 * nmj;

/* Values for title_type:
   1: Movie (single part)
   2: TV Series
   3: Episode
   5: Season
   6: Movie (multipart)
   
 */

static bg_cmdline_arg_t global_options[] =
  {
    {
      .arg =         "-root",
      .help_string = "Root directory of the database",
      .argv         = &path,
    },
    { }
  };

const bg_cmdline_app_data_t app_data =
  {
    .package =  PACKAGE,
    .version =  VERSION,
    .name =     "gmerlin-db2nmj",
    .long_name = TRS("Convert a gmerlin media db into the nmj-2.0.0 format"),
    .synopsis = TRS("[options]\n"),
    .help_before = TRS("gmerlin database to nmj translator\n"),
    .args = (bg_cmdline_arg_array_t[]) { { TRS("Options"), global_options },
                                       {  } },
    .files = (bg_cmdline_ext_doc_t[])
    { { "~/.gmerlin/plugins.xml",
        TRS("Cache of the plugin registry (shared by all applications)") },
      { "~/.gmerlin/generic/cfg.xml",
        TRS("Default plugin parameters are read from there. Use gmerlin_plugincfg to change them.") },
      { /* End */ }
    },
    
  };

static const struct
  {
  char c;
  char * escaped;
  }
escape_rules[] =
  {
    { '\'', "&apos;" },
    { '&',  "&amp;" },
    { /* End */      }
  };

static char * escape_string(const char * str)
  {
  int done;
  int i;
  const char * pos;
  char * ret = NULL;
  char buf[2];

  if(!str)
    return NULL;
  
  buf[1] = '\0';

  pos = str;
  while(*pos != '\0')
    {
    done = 0;
    i = 0;
    while(escape_rules[i].escaped)
      {
      if(escape_rules[i].c == *pos)
        {
        ret = gavl_strcat(ret, escape_rules[i].escaped);
        done = 1;
        break;
        }
      i++;
      }
    if(!done)
      {
      buf[0] = *pos;
      ret = gavl_strcat(ret, buf);
      }
    pos++;
    }
  return ret;
  }

/*
 *  Categories are summed up from the following:
 *  
 *   3: Video
 *   4: Video (private)
 *  16: Photo
 *  40: Music
 */

static void query_scan_dir_callback(void * priv, void * obj)
  {
  char * sql;
  bg_db_dir_t * dir = obj;

  int category = 0;

  if(dir->scan_flags & BG_DB_SCAN_AUDIO)
    category += 40;
  
  if(dir->scan_flags & BG_DB_SCAN_VIDEO)
    category += 3;

  if(dir->scan_flags & BG_DB_SCAN_PHOTO)
    category += 16;
  
  sql = sqlite3_mprintf("INSERT INTO SCAN_DIRS ( ID, DIRECTORY, NAME, SIZE, CATEGORY, STATUS ) VALUES "
                        "( %"PRId64", %Q, %Q, %"PRId64", %d, '3')",
                        bg_db_object_get_id(dir),
                        dir->path + root_dir_len, dir->obj.label, dir->obj.size, category);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  }

static const struct
  {
  const char * mimetype;
  const char * format;
  }
mimetypes[] =
  {
    { "audio/mpeg", "MPEG Audio" },
    { "audio/flac", "Flac"       },
    { "audio/ogg",  "Vorbis"     },
    { "image/jpeg", "JPEG"       },
    { "video/x-msvideo", "AVI"   },
    { "video/mpeg",      "MPEG-1"   },
    { "video/MP2P",      "MPEG-2"   },
    { "video/x-matroska",  "Matroska"   },
    { "video/x-flv", "Flash Video" },
    { "video/mp4",   "MP4" },
    { /* End */ },
  };
  
static const char * mimetype_to_format(const char * mimetype)
  {
  int i = 0;

  if(mimetype) // Prevent crash
    {
    while(mimetypes[i].mimetype)
      {
      if(!strcmp(mimetypes[i].mimetype, mimetype))
        return mimetypes[i].format;
      i++;
      }
    }
  
  return "Unknown";
  }

static void query_audio_file_callback(void * priv, void * obj)
  {
  char * sql;
  bg_db_audio_file_t * af = obj;
  int64_t id;
  
  char date[BG_DB_DATE_STRING_LEN];
  char mtime[BG_DB_TIME_STRING_LEN];
    
  char * title = escape_string(af->title);
  char * search_title = escape_string(af->search_title);
  char * artist = escape_string(af->artist);

  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Song: %s: %s", af->artist, af->title);
  
  /* SONGS */
  
  sql = sqlite3_mprintf("INSERT INTO SONGS ( "
                        "ID,"
                        "TITLE,"
                        "SEARCH_TITLE,"
                        "PATH,"
                        "SCAN_DIRS_ID,"
                        "RUNTIME,"
                        "FORMAT,"
                        "RATING,"
                        "SIZE,"
                        "PLAY_COUNT,"
                        "BIT_RATE,"
                        "TRACK_POSITION,"
                        "RELEASE_DATE,"
                        "CREATE_TIME,"
                        "UPDATE_STATE "
                        " ) VALUES ( "
                        "%"PRId64"," // ID
                        "%Q,"        // TITLE
                        "%Q,"        // SEARCH_TITLE
                        "%Q,"        // PATH
                        "%"PRId64"," // SCAN_DIRS_ID
                        "%"PRId64"," // RUNTIME
                        "%Q,"        // FORMAT
                        "0,"         // RATING
                        "%"PRId64"," // SIZE
                        "0,"         // PLAY_COUNT
                        "%Q,"        // BIT_RATE
                        "%d,"        // TRACK_POSITION
                        "%Q,"        // RELEASE_DATE
                        "%Q,"        // CREATE_TIME
                        "2 );",      // UPDATE_STATE
                        bg_db_object_get_id(af),
                        title,
                        search_title,
                        af->file.path + root_dir_len,
                        af->file.scan_dir_id,
                        af->file.obj.duration / GAVL_TIME_SCALE,
                        mimetype_to_format(af->file.mimetype),
                        af->file.obj.size,
                        af->bitrate,
                        af->track,
                        bg_db_date_to_string(&af->date, date),
                        bg_db_time_to_string(af->file.mtime, mtime));
  
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_PERSONS */

  sql = sqlite3_mprintf("INSERT OR IGNORE INTO SONG_PERSONS ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                        af->artist_id, artist);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_PERSONS_SONGS */

  id = bg_sqlite_get_next_id(nmj, "SONG_PERSONS_SONGS");

  sql = sqlite3_mprintf("INSERT INTO SONG_PERSONS_SONGS ( ID, PERSONS_ID, SONGS_ID, PERSON_TYPE ) VALUES ( %"PRId64", %"PRId64", %"PRId64", 'ARTIST' );",
                        id, af->artist_id, bg_db_object_get_id(af));
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  
  /* SONG_GENRES */
  sql = sqlite3_mprintf("INSERT OR IGNORE INTO SONG_GENRES ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                        af->genre_id, af->genre);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_GENRES_SONGS */

  id = bg_sqlite_get_next_id(nmj, "SONG_GENRES_SONGS");

  sql = sqlite3_mprintf("INSERT INTO SONG_GENRES_SONGS ( ID, SONGS_ID, GENRES_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64" );",
                        id, bg_db_object_get_id(af), af->genre_id);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  free(title);
  free(search_title);
  free(artist);
  }

static void query_audio_album_song_callback(void * priv, void * obj)
  {
  int64_t id;
  bg_db_audio_file_t * af = obj;
  char * sql;
  
  id = bg_sqlite_get_next_id(nmj, "SONG_ALBUMS_SONGS");

  sql = sqlite3_mprintf("INSERT INTO SONG_ALBUMS_SONGS ( ID, ALBUMS_ID, SONGS_ID, SEQUENCE ) "
                        "VALUES "
                        "( %"PRId64", %"PRId64", %"PRId64", %"PRId64" );",
                        id, af->album_id, bg_db_object_get_id(obj), af->track);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  }

static void query_audio_album_callback(void * priv, void * obj)
  {
  int64_t group_id;
  char * sql;
  bg_db_audio_album_t * a = obj;
  int64_t id;
  const char * group;
  bg_db_image_file_t * cover;
  bg_db_image_file_t * cover_small;
  bg_db_image_file_t * thumb;
  
  char date[BG_DB_DATE_STRING_LEN];
  char mtime[BG_DB_TIME_STRING_LEN];
  
  char * title = escape_string(a->title);
  char * search_title = escape_string(a->search_title);
  char * artist = escape_string(a->artist);

  /* Group */
  group = bg_db_get_group(artist, &group_id);

  /* Hack */
  if(!strcmp(group, "Others"))
    group = "_OTHERS";
  /* /Hack */
  
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Album: %s: %s", a->artist, a->title);
    
  // SONG_ALBUMS
  
  sql = sqlite3_mprintf("INSERT INTO SONG_ALBUMS ( "
                        "ID,"
                        "TITLE,"
                        "SEARCH_TITLE,"
                        "TOTAL_ITEM,"
                        "RELEASE_DATE,"
                        "UPDATE_STATE"
                        ") VALUES ("
                        "%"PRId64"," // ID
                        "%Q,"        // TITLE
                        "%Q,"        // SEARCH_TITLE
                        "'%d',"      // TOTAL_ITEM
                        "%Q,"        // RELEASE_DATE
                        "3);",       // UPDATE_STATE
                        bg_db_object_get_id(obj),
                        title,
                        search_title,
                        a->obj.children,
                        bg_db_date_to_string(&a->date, date));
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  
  // SONG_ALBUMS_SONGS
  bg_db_query_children(db, a, query_audio_album_song_callback, NULL,
                       0, 0, NULL);


  /* SONG_GENRES */
  sql = sqlite3_mprintf("INSERT OR IGNORE INTO SONG_GENRES ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                        a->genre_id, a->genre);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_GENRES_SONG_ALBUMS */
  id = bg_sqlite_get_next_id(nmj, "SONG_GENRES_SONG_ALBUMS");

  sql = sqlite3_mprintf("INSERT INTO SONG_GENRES_SONG_ALBUMS ( ID, ALBUMS_ID, GENRES_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64" );",
                        id, bg_db_object_get_id(a), a->genre_id);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_PERSONS */

  sql = sqlite3_mprintf("INSERT OR IGNORE INTO SONG_PERSONS ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                        a->artist_id, artist);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_GROUPS */
  
  sql = sqlite3_mprintf("INSERT OR IGNORE INTO SONG_GROUPS ( ID, NAME, LANGUAGE ) VALUES ( %"PRId64", %Q, 'EN' );",
                        group_id, group);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_GROUPS_SONG_ALBUMS */
  
  sql = sqlite3_mprintf("INSERT INTO SONG_GROUPS_SONG_ALBUMS ( ID, GROUPS_ID, ALBUMS_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64" );",
                        bg_db_object_get_id(a), group_id, bg_db_object_get_id(a));
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_PERSONS_SONG_ALBUMS */

  sql = sqlite3_mprintf("INSERT INTO SONG_PERSONS_SONG_ALBUMS ( ID, PERSONS_ID, ALBUMS_ID, PERSON_TYPE, CUSTOM1 ) VALUES ( %"PRId64", %"PRId64", %"PRId64", 'ARTIST', '%d' );",
                        bg_db_object_get_id(a), a->artist_id, bg_db_object_get_id(a), group_id);
  
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  /* SONG_ALBUM_POSTERS */

  if(a->cover_id <= 0)
    return;

  cover = bg_db_object_query(db, a->cover_id);
  cover_small = bg_db_get_thumbnail(db, a->cover_id, 600, 600, 0, "image/jpeg");
  thumb = bg_db_get_thumbnail(db, a->cover_id, 248, 248, 0, "image/jpeg");

  if(cover_small && thumb)
    {
    sql = sqlite3_mprintf("INSERT INTO SONG_ALBUM_POSTERS ( ID, POSTER, THUMBNAIL, CREATE_TIME ) VALUES ( %"PRId64", %Q, %Q, %Q );",
                          bg_db_object_get_id(a),
                          cover_small->file.path + root_dir_len,
                          thumb->file.path + root_dir_len, bg_db_time_to_string(cover->file.mtime, mtime));
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);
    }

  if(cover)
    bg_db_object_unref(cover);
  if(cover_small)
    bg_db_object_unref(cover_small);
  if(thumb)
    bg_db_object_unref(thumb);

  free(title);
  free(search_title);
  free(artist);
  
  }

static int64_t pls_id;
static int pls_index;

static void query_playlist_item_callback(void * priv, void * obj)
  {
  char * sql;
  int64_t id;
  id = bg_sqlite_get_next_id(nmj, "SONG_PLS_ITEM");

  sql = sqlite3_mprintf("INSERT INTO SONG_PLS_ITEM ( ID, PLS_ID, SONGS_ID, SEQUENCE ) "
                        "VALUES "
                        "( %"PRId64", %"PRId64", %"PRId64", %d );",
                        id, pls_id, bg_db_object_get_id(obj), pls_index);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  pls_index++;  
  }

static void query_playlist_callback(void * priv, void * obj)
  {
  char * sql;
  bg_db_object_t * p = obj;
  char time_str[BG_DB_TIME_STRING_LEN];
  char * path = bg_sprintf("MUSIC/PLAYLISTS/%s.M3U", p->label);
  time_t t = time(NULL);
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Playlist: %s", p->label);
  
  /* SONG_PLS */
  sql = sqlite3_mprintf("INSERT INTO SONG_PLS ( ID, NAME, PATH, TOTAL_ITEM, CREATE_TIME ) VALUES ( %"PRId64", %Q, %Q, '%d', %Q );",
                        bg_db_object_get_id(p),
                        p->label, path, p->children, bg_db_time_to_string(t, time_str));

  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  free(path);
  
  /* SONG_PLS_ITEM */

  pls_id = bg_db_object_get_id(p);
  pls_index = 1;
  
  bg_db_query_children(db, p, query_playlist_item_callback, NULL,
                       0, 0, NULL);
    
  }

 /*
  * Public Domain implementation by Kamil Dziobek. turbos11(at)gmail.com
  * This code implements Gibest hash algorithm first use in Media Player Classics
  * For more implementation(various languages and authors) see:
  * http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes   
  *
  * -works only on little-endian procesor DEC, Intel and compatible
  * -sizeof(unsigned long long) must be 8
  *
  *
  * Changed for gmerlin to use uint64_t
  */


static uint64_t analizefileOSHahs(char *fileName)
  {
  FILE        *file;
  int i;
  uint64_t t1=0;
  uint64_t buffer1[8192*2];
  file = fopen(fileName, "rb");
  if(!file)
    {
    gavl_log(GAVL_LOG_ERROR, LOG_DOMAIN, "Cannot analyze file %s: %s",
           fileName, strerror(errno));
    return 0;
    }
  fread(buffer1, 8192, 8, file);
  fseek(file, -65536, SEEK_END);
  fread(&buffer1[8192], 8192, 8, file); 
  for (i=0;i<8192*2;i++)
    t1+=buffer1[i];
  t1+= ftell(file); //add filesize
  fclose(file); 
  return  t1;
  };

static void translate_video_file(bg_db_video_file_t * f)
  {
  char * sql;
  char time_str[BG_DB_TIME_STRING_LEN];
  time_t t = time(NULL);

  /* Videos */
  sql = sqlite3_mprintf("INSERT INTO VIDEOS ( "
                        "ID, "
                        "PATH, "
                        "FILE_TYPE, "
                        "SCAN_DIRS_ID, "
                        "CREATE_TIME, "
                        "UPDATE_STATE, "
                        "HASH, "
                        "SIZE, "
                        "THREE_D, "
                        "PLAY_COUNT "
                        ") VALUES ( "
                        "%"PRId64", "
                        "%Q, "
                        "3, "
                        "%"PRId64", "
                        "%Q, "
                        "'2', "
                        "'%016"PRIx64"', "
                        "%"PRId64", "
                        "0, "
                        "0"
                        ");",
                        bg_db_object_get_id(f),
                        f->file.path + root_dir_len,
                        f->file.scan_dir_id,
                        bg_db_time_to_string(t, time_str),
                        analizefileOSHahs(f->file.path),
                        f->file.obj.size);

  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  sql = sqlite3_mprintf("INSERT INTO VIDEO_PROPERTIES ( "
                        "ID, "
                        "RUNTIME, "
                        "RESOLUTION, "
                        "WIDTH, "
                        "HEIGHT, "
                        "ASPECT_RATIO, "
                        "SYSTEM, "
                        "VIDEO_CODEC, "
                        "FPS "
                        ") VALUES ("
                        "%"PRId64", "
                        "%"PRId64", "
                        "'%dx%d', "
                        "'%d', "
                        "'%d', "
                        "'%d:%d', "
                        "%Q, "
                        "%Q, "
                        "'%.3f'"
                        ");",
                        bg_db_object_get_id(f),
                        f->file.obj.duration / GAVL_TIME_SCALE,
                        f->width, f->height,
                        f->width, f->height,
                        f->aspect_num, f->aspect_den,
                        mimetype_to_format(f->file.mimetype),
                        f->video_codec,
                        f->frame_duration ? (double)f->timescale / (double)f->frame_duration : (double)f->timescale);
  
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  }

static void translate_video_info(bg_db_video_info_t * f, int64_t id,
                                 int total_items, gavl_time_t total_duration, int title_type,
                                 const char * title, const char * search_title)
  {
  int64_t group_id;
  const char * group;
  char * synopsis;
  
  char * sql;
  char time_str[BG_DB_TIME_STRING_LEN];
  char date_str[BG_DB_DATE_STRING_LEN];
  time_t t = time(NULL);
  int64_t next_id;
  int i;
  bg_db_time_to_string(t, time_str);

  if(!title)
    title = f->title;
  if(!search_title)
    search_title = f->search_title;
    
  sql = sqlite3_mprintf("INSERT INTO SHOWS ( "
                        "ID, "
                        "TITLE, "
                        "SEARCH_TITLE, "
                        "TOTAL_ITEM, "
                        "YEAR, "
                        "RELEASE_DATE, "
                        "RATING, "
                        "PARENTAL_CONTROL, "
                        "RUNTIME, "
                        "CREATE_TIME, "
                        "UPDATE_STATE, "
                        "TITLE_TYPE"
                        ") VALUES ("
                        "%"PRId64", "
                        "%Q, "
                        "%Q, "
                        "%d, "
                        "'%d', "
                        "%Q, "
                        "%s, "
                        "%Q, "
                        "%"PRId64", "
                        "%Q, "
                        "2, "
                        "%d);",
                        id,
                        title,
                        search_title,
                        total_items,
                        f->date.year,
                        bg_db_date_to_string(&f->date, date_str),
                        f->rating ? f->rating : "0.0",
                        f->parental_control,
                        total_duration / GAVL_TIME_SCALE,
                        time_str,
                        title_type);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  if(title_type != 3)
    {
    /* Group */

    group = bg_db_get_group(search_title, &group_id);
  
    /* SHOW_GROUPS */
  
    sql = sqlite3_mprintf("INSERT OR IGNORE INTO SHOW_GROUPS ( ID, NAME, LANGUAGE ) VALUES ( %d, %Q, 'EN' );",
                          group_id, group);
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);

    /* SHOW_GROUPS_SHOWS */
  
    sql = sqlite3_mprintf("INSERT INTO SHOW_GROUPS_SHOWS ( ID, GROUPS_ID, SHOWS_ID, TITLE_TYPE ) VALUES ( %"PRId64", %"PRId64", %"PRId64", %d );",
                          id, group_id, id, title_type);
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);
    }
  
  
  /* Genres */

  if(f->genres)
    {
    i = 0;
    while(f->genres[i])
      {
      sql = sqlite3_mprintf("INSERT OR IGNORE INTO VIDEO_GENRES ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                            f->genre_ids[i], f->genres[i]);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);

      next_id = bg_sqlite_get_next_id(nmj, "SHOWS_GENRES");

      sql = sqlite3_mprintf("INSERT INTO SHOWS_GENRES ( ID, GENRES_ID, SHOWS_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64" );",
                            next_id, f->genre_ids[i], id);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);
      
      i++;
      }
    }

  /* Directors */
  if(f->directors)
    {
    i = 0;
    while(f->directors[i])
      {
      sql = sqlite3_mprintf("INSERT OR IGNORE INTO VIDEO_PERSONS ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                            f->director_ids[i], f->directors[i]);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);

      next_id = bg_sqlite_get_next_id(nmj, "SHOWS_PERSONS");

      sql = sqlite3_mprintf("INSERT INTO SHOWS_PERSONS ( ID, PERSONS_ID, SHOWS_ID, PERSON_TYPE ) VALUES ( %"PRId64", %"PRId64", %"PRId64", 'DIRECTOR' );",
                            next_id, f->director_ids[i], id);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);
      
      i++;
      }
    }

  /* Actors */
  if(f->actors)
    {
    i = 0;
    while(f->actors[i])
      {
      sql = sqlite3_mprintf("INSERT OR IGNORE INTO VIDEO_PERSONS ( ID, NAME ) VALUES ( %"PRId64", %Q );",
                            f->actor_ids[i], f->actors[i]);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);

      next_id = bg_sqlite_get_next_id(nmj, "SHOWS_PERSONS");

      sql = sqlite3_mprintf("INSERT INTO SHOWS_PERSONS ( ID, PERSONS_ID, SHOWS_ID, PERSON_TYPE ) VALUES ( %"PRId64", %"PRId64", %"PRId64", 'CAST' );",
                            next_id, f->actor_ids[i], id);
      bg_sqlite_exec(nmj, sql, NULL, NULL);
      sqlite3_free(sql);
      
      i++;
      }
    }

  /* Synopsis */

  synopsis = NULL;

  if(f->title_orig)
    synopsis = bg_sprintf("OT: %s\n", f->title_orig);
  
  if(f->countries)
    {
    i = 0;
    while(f->countries[i])
      {
      if(i)
        synopsis = gavl_strcat(synopsis, ", ");
      synopsis = gavl_strcat(synopsis, f->countries[i]);
      i++;
      }
    }

  /* Audio languages */
  if(f->audio_languages && f->audio_languages[0])
    {
    if(synopsis)
      synopsis = gavl_strcat(synopsis, "\n");
    synopsis = gavl_strcat(synopsis, "A: ");
    i = 0;
    while(f->audio_languages[i])
      {
      if(i)
        synopsis = gavl_strcat(synopsis, ", ");
      synopsis = gavl_strcat(synopsis, bg_get_language_name(f->audio_languages[i]));
      i++;
      }
    }
  
  /* Subtitle languages */
  if(f->subtitle_languages && f->subtitle_languages[0])
    {
    if(synopsis)
      synopsis = gavl_strcat(synopsis, "\n");
    synopsis = gavl_strcat(synopsis, "S: ");
    i = 0;
    while(f->subtitle_languages[i])
      {
      if(i)
        synopsis = gavl_strcat(synopsis, ", ");
      synopsis = gavl_strcat(synopsis, bg_get_language_name(f->subtitle_languages[i]));
      i++;
      }
    }
  
  if(f->plot)
    {
    if(synopsis)
      synopsis = gavl_strcat(synopsis, "\n");
    synopsis = gavl_strcat(synopsis, f->plot);
    }

  if(synopsis)
    {
    sql = sqlite3_mprintf("INSERT INTO SYNOPSISES ( ID, SUMMARY ) VALUES ( %"PRId64", %Q );",
                          id, synopsis);
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);
    free(synopsis);
    }
  
  
  /* Images */

  if((f->poster_id > 0) || (f->fanart_id > 0))
    {
    bg_db_file_t * poster = NULL;
    bg_db_file_t * poster_thumb = NULL;
    
    bg_db_file_t * wallpaper = NULL;

    if(f->poster_id)
      {
      poster = bg_db_get_thumbnail(db, f->poster_id, 220, 330, 0, "image/jpeg");
      poster_thumb = bg_db_get_thumbnail(db, f->poster_id, 124, 185, 0, "image/jpeg");
      }

    if(f->fanart_id > 0)
      wallpaper = bg_db_get_thumbnail(db, f->fanart_id, 1280, 720, 0, "image/jpeg");

    sql = sqlite3_mprintf("INSERT INTO VIDEO_POSTERS ( "
                          "ID, "
                          "POSTER, "
                          "THUMBNAIL, "
                          "WALLPAPER, "
                          "TYPE, "
                          "CREATE_TIME "
                          ") VALUES ( "
                          "%"PRId64", "
                          "%Q, "
                          "%Q, "
                          "%Q, "
                          "1, "
                          "%Q);",
                          id,
                          (poster ? poster->path + root_dir_len : NULL),
                          (poster_thumb ? poster_thumb->path + root_dir_len : NULL),
                          (wallpaper ? wallpaper->path + root_dir_len : NULL),
                          time_str);

    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);

    if(poster)
      bg_db_object_unref(poster);
    if(poster_thumb)
      bg_db_object_unref(poster_thumb);
    if(wallpaper)
      bg_db_object_unref(wallpaper);
    
    }
  else // Add dummy entry
    {
    sql = sqlite3_mprintf("INSERT INTO VIDEO_POSTERS ( "
                          "ID, "
                          "CREATE_TIME "
                          ") VALUES ( "
                          "%"PRId64", "
                          "%Q);",
                          id,
                          time_str);
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);
    }
  
  }

static int64_t multipart_movie_duration;
static int multipart_movie_items;

static void query_movie_part_callback(void * priv, void * obj)
  {
  int64_t id;
  char * sql;
  bg_db_video_file_t * f = obj;

  
  translate_video_file(f);
  multipart_movie_duration += f->file.obj.duration;
  multipart_movie_items++;

  id = bg_sqlite_get_next_id(nmj, "SHOWS_VIDEOS");
  sql = sqlite3_mprintf("INSERT INTO SHOWS_VIDEOS ( ID, SHOWS_ID, VIDEOS_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64");",
                        id, f->collection, bg_db_object_get_id(f));
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  

  }

static void query_movie_callback(void * priv, void * obj)
  {
  if(bg_db_object_get_type(obj) == BG_DB_OBJECT_MOVIE)
    {
    int64_t id;
    char * sql;
    bg_db_movie_t * m = obj;

    gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating movie %s", m->info.title);
        
    /* Save file details */
    translate_video_file(&m->file);
    translate_video_info(&m->info, bg_db_object_get_id(obj),
                         1, m->file.file.obj.duration, 1, NULL, NULL);

    id = bg_sqlite_get_next_id(nmj, "SHOWS_VIDEOS");
    sql = sqlite3_mprintf("INSERT INTO SHOWS_VIDEOS ( ID, SHOWS_ID, VIDEOS_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64");",
                          id, bg_db_object_get_id(m), bg_db_object_get_id(m));
    bg_sqlite_exec(nmj, sql, NULL, NULL);
    sqlite3_free(sql);
    }
  else if(bg_db_object_get_type(obj) == BG_DB_OBJECT_MOVIE_MULTIPART)
    {
    bg_db_video_container_t * m = obj;
    multipart_movie_duration = 0;
    multipart_movie_items = 0;

    gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating movie %s", m->info.title);
    
    bg_db_query_children(db, obj, query_movie_part_callback, NULL,
                         0, 0, NULL);

    translate_video_info(&m->info, bg_db_object_get_id(obj),
                         multipart_movie_items, multipart_movie_duration, 6, NULL, NULL);
    }
  }

/* TV Series */

typedef struct
  {
  int total_items;
  int64_t total_duration;

  int season_items;
  int64_t season_duration;
  
  int64_t series;
  int64_t season;
  int season_index;
  const char * series_title;
  const char * series_search_title;
  } tv_t;

static int get_season_index(const char * label)
  {
  const char * pos = label + (strlen(label) - 1);
  while(isdigit(*pos))
    pos--;
  pos++;
  return atoi(pos);
  }

static void query_episode_callback(void * priv, void * obj)
  {
  tv_t * t;
  int64_t id;
  bg_db_movie_t * m = obj;
  char * sql;
  
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating episode %s", m->info.title);

  t = priv;
  
  /* Save file details */
  translate_video_file(&m->file);
  translate_video_info(&m->info, bg_db_object_get_id(obj),
                       1, m->file.file.obj.duration, 3, NULL, NULL);

  id = bg_sqlite_get_next_id(nmj, "SHOWS_VIDEOS");
  sql = sqlite3_mprintf("INSERT INTO SHOWS_VIDEOS ( ID, SHOWS_ID, VIDEOS_ID ) VALUES ( %"PRId64", %"PRId64", %"PRId64");",
                        id, bg_db_object_get_id(m), bg_db_object_get_id(m));
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);

  id = bg_sqlite_get_next_id(nmj, "EPISODES");
  sql = sqlite3_mprintf("INSERT INTO EPISODES ( ID, EPISODE_ID, SERIES_ID, SEASON_ID, SEASON, EPISODE ) VALUES ( %"PRId64", %"PRId64", %"PRId64", %"PRId64", %d, %d);",
                        id, bg_db_object_get_id(m), t->series, t->season, t->season_index, m->file.index);
  bg_sqlite_exec(nmj, sql, NULL, NULL);
  sqlite3_free(sql);
  
  t->season_items++;
  t->season_duration += m->file.file.obj.duration;
  }

static void query_season_callback(void * priv, void * obj)
  {
  tv_t * t;
  bg_db_video_container_t * c = obj;
  char * title;
  char * search_title;
  
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating season %s", c->info.title);

  t = priv;
  t->season_items = 0;
  t->season_duration = 0;
  t->season = bg_db_object_get_id(obj);
  t->season_index = get_season_index(c->info.title);

  title = bg_sprintf("%s %s", t->series_title, c->info.title);
  search_title = bg_sprintf("%s %s", t->series_search_title, c->info.title);
  
  bg_db_query_children(db, obj, query_episode_callback, priv,
                       0, 0, NULL);
  
  translate_video_info(&c->info, bg_db_object_get_id(obj),
                       t->season_items, t->season_duration, 5, title, search_title);
  free(title);
  free(search_title);
    
  t->total_items += t->season_items;
  t->total_duration += t->season_duration;
  }
  
static void query_tvseries_callback(void * priv, void * obj)
  {
  bg_db_video_container_t * c = obj;
  tv_t tv;
  memset(&tv, 0, sizeof(tv));

  tv.series = bg_db_object_get_id(obj);
  tv.series_title = c->info.title;
  tv.series_search_title = c->info.search_title;
  
  bg_db_query_children(db, obj, query_season_callback, &tv,
                       0, 0, NULL);
  
  translate_video_info(&c->info, bg_db_object_get_id(obj),
                       tv.total_items, tv.total_duration, 2, NULL, NULL);
  
  }

int main(int argc, char ** argv)
  {
  bg_cfg_section_t * cfg_section;
  char * tmp_path;
  bg_plugin_registry_t * plugin_reg;
  bg_cfg_registry_t * cfg_reg;
  char * sql;
  void * parent;
  
  bg_cmdline_init(&app_data);
  bg_cmdline_parse(global_options, &argc, &argv, NULL);

  if(!bg_cmdline_check_unsupported(argc, argv))
    return -1;

  /* Create plugin registry */
  cfg_reg = bg_cfg_registry_create();
  tmp_path =  bg_search_file_read("generic", "cfg.xml");
  bg_cfg_registry_load(cfg_reg, tmp_path);
  if(tmp_path)
    free(tmp_path);
  
  cfg_section = bg_cfg_registry_find_section(cfg_reg, "plugins");
  plugin_reg = bg_plugin_registry_create(cfg_section);

  if(chdir(path))
    {
    gavl_log(GAVL_LOG_ERROR, LOG_DOMAIN, "Couldn't change directory to %s", path);
    return -1;
    }

  if(!getcwd(root_dir, ROOT_DIR_SIZE-2))
    {
    gavl_log(GAVL_LOG_ERROR, LOG_DOMAIN, "Couldn't get current directory");
    return -1;
    }

  strcat(root_dir, "/");

  root_dir_len = strlen(root_dir);
  
  db = bg_db_create(path, plugin_reg, 0);
  if(!db)
    return -1;

  nmj = bg_nmj_create();
  if(!nmj)
    return -1;

  /* Scan dirs */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating scan directories");

  parent = bg_db_rootfolder_get(db, BG_DB_OBJECT_DIRECTORY);

  if(parent)
    {
    sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d) & (PARENT_ID = %"PRId64");",
                          BG_DB_OBJECT_DIRECTORY, bg_db_object_get_id(parent));
    bg_db_query_sql(db, sql, query_scan_dir_callback, NULL);
    sqlite3_free(sql);
    bg_db_object_unref(parent);
    }
  

  /* Songs */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating audio files");
  sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d)",
                        BG_DB_OBJECT_AUDIO_FILE);
  bg_db_query_sql(db, sql, query_audio_file_callback, NULL);
  sqlite3_free(sql);

  /* Albums */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating audio albums");
  sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d)",
                        BG_DB_OBJECT_AUDIO_ALBUM);
  bg_db_query_sql(db, sql, query_audio_album_callback, NULL);
  sqlite3_free(sql);

  /* Playlists */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating playlists");
  sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d)",
                        BG_DB_OBJECT_PLAYLIST);
  bg_db_query_sql(db, sql, query_playlist_callback, NULL);
  sqlite3_free(sql);

  /* Movies */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating movies");
  sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d) | (TYPE = %d)",
                        BG_DB_OBJECT_MOVIE, BG_DB_OBJECT_MOVIE_MULTIPART);
  bg_db_query_sql(db, sql, query_movie_callback, NULL);
  sqlite3_free(sql);

  /* TV Series */
  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Translating TV Series");
  sql = sqlite3_mprintf("SELECT ID FROM OBJECTS WHERE (TYPE = %d)",
                        BG_DB_OBJECT_TVSERIES);
  bg_db_query_sql(db, sql, query_tvseries_callback, NULL);
  sqlite3_free(sql);
  
  
  
  /* Close databases */
  bg_sqlite_exec(nmj, "END;", NULL, NULL);

  bg_db_destroy(db);
  sqlite3_close(nmj);
  
  return 0;
  }
