/*
 * $Id$
 *
 * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
 * Copyright (c) 2002-2014, Professor Benoit Macq
 * Copyright (c) 2010-2011, Kaori Hagihara
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cache_manager.h"

cachelist_param_t * gene_cachelist(void)
{
  cachelist_param_t *cachelist;
  
  cachelist = (cachelist_param_t *)malloc( sizeof(cachelist_param_t));
  
  cachelist->first = NULL;
  cachelist->last  = NULL;

  return cachelist;
}

void delete_cachelist(cachelist_param_t **cachelist)
{
  cache_param_t *cachePtr, *cacheNext;
  
  cachePtr = (*cachelist)->first;
  while( cachePtr != NULL){
    cacheNext=cachePtr->next;
    delete_cache( &cachePtr);
    cachePtr=cacheNext;
  }
  free( *cachelist);
}

cache_param_t * gene_cache( const char *targetname, int csn, char *tid, char *cid)
{
  cache_param_t *cache;
  
  cache = (cache_param_t *)malloc( sizeof(cache_param_t));
  cache->filename = strdup( targetname);
  cache->tid = strdup( tid);
  cache->csn = csn;
  cache->cid = (char **)malloc( sizeof(char *));
  *cache->cid = strdup( cid);
  cache->numOfcid = 1;
#if 1
  cache->metadatalist = NULL;
#else
  cache->metadatalist = gene_metadatalist();
#endif
  cache->ihdrbox = NULL;
  cache->next = NULL;

  return cache;
}

void delete_cache( cache_param_t **cache)
{
  int i;
  
  free( (*cache)->filename);
  free( (*cache)->tid);

  delete_metadatalist( &(*cache)->metadatalist);

  if((*cache)->ihdrbox)
    free((*cache)->ihdrbox);
  for( i=0; i<(*cache)->numOfcid; i++)
    free( (*cache)->cid[i]);
  free( (*cache)->cid);
  free( *cache);
}

void insert_cache_into_list( cache_param_t *cache, cachelist_param_t *cachelist)
{
  if( cachelist->first)
    cachelist->last->next = cache;
  else
    cachelist->first = cache;
  cachelist->last = cache;
}

cache_param_t * search_cache( const char targetname[], cachelist_param_t *cachelist)
{
  cache_param_t *foundcache;

  if( !targetname)
    return NULL;

  foundcache = cachelist->first;
  
  while( foundcache != NULL){
    
    if( strcmp( targetname, foundcache->filename) == 0)
      return foundcache;
      
    foundcache = foundcache->next;
  }
  return NULL;
}

cache_param_t * search_cacheBycsn( int csn, cachelist_param_t *cachelist)
{
  cache_param_t *foundcache;

  foundcache = cachelist->first;
  
  while( foundcache != NULL){
    
    if(  csn == foundcache->csn)
      return foundcache;
    foundcache = foundcache->next;
  }
  return NULL;
}

cache_param_t * search_cacheBycid( const char cid[], cachelist_param_t *cachelist)
{
  cache_param_t *foundcache;
  int i;

  if( !cid)
    return NULL;

  foundcache = cachelist->first;
  
  while( foundcache != NULL){
    for( i=0; i<foundcache->numOfcid; i++)
      if( strcmp( cid, foundcache->cid[i]) == 0)
	return foundcache;
    foundcache = foundcache->next;
  }
  return NULL;
}

cache_param_t * search_cacheBytid( const char tid[], cachelist_param_t *cachelist)
{
  cache_param_t *foundcache;

  if( !tid)
    return NULL;

  foundcache = cachelist->first;
  
  while( foundcache != NULL){
    if( strcmp( tid, foundcache->tid) == 0)
      return foundcache;
    foundcache = foundcache->next;
  }
  return NULL;
}

void add_cachecid( const char *cid, cache_param_t *cache)
{
  if( !cid)
    return;
  
  if( (cache->cid = realloc( cache->cid, (OPJ_SIZE_T)(cache->numOfcid+1)*sizeof(char *))) == NULL){
    fprintf( stderr, "failed to add new cid to cache table in add_cachecid()\n");
    return;
  }
  
  cache->cid[ cache->numOfcid] = strdup( cid);

  cache->numOfcid ++;
}

void update_cachetid( const char *tid, cache_param_t *cache)
{
  if( !tid)
    return;

  if( tid[0] != '0' && strcmp( tid, cache->tid) !=0){
    fprintf( stderr, "tid is updated to %s for %s\n", tid, cache->filename);
    free( cache->tid);
    cache->tid = strdup( tid);
  }
}

void remove_cidInCache( const char *cid, cache_param_t *cache);

void remove_cachecid( const char *cid, cachelist_param_t *cachelist)
{
  cache_param_t *cache;

  cache = search_cacheBycid( cid, cachelist);
  remove_cidInCache( cid, cache);
}

void remove_cidInCache( const char *cid, cache_param_t *cache)
{
  int idx = -1;
  char **tmp;
  int i, j;

  for( i=0; i<cache->numOfcid; i++)
    if( strcmp( cid, cache->cid[i]) == 0){
      idx = i;
      break;
    }

  if( idx == -1){
    fprintf( stderr, "cid: %s not found\n", cid);
    return;   
  }
  
  tmp = cache->cid;

  cache->cid = (char **)malloc( (OPJ_SIZE_T)(cache->numOfcid-1)*sizeof(char *));
  
  for( i=0, j=0; i<cache->numOfcid; i++){
    if( i != idx){
      cache->cid[j] = strdup( tmp[i]);
      j++;
    }
    free( tmp[i]);
  }
  free( tmp);

  cache->numOfcid --;
}

void print_cache( cache_param_t *cache)
{
  int i;
  
  fprintf( stdout,"cache\n");
  fprintf( stdout,"\t filename: %s\n", cache->filename);
  fprintf( stdout,"\t tid: %s\n", cache->tid);
  fprintf( stdout,"\t csn: %d\n", cache->csn);
  fprintf( stdout,"\t cid:");

  for( i=0; i<cache->numOfcid; i++)
    fprintf( stdout," %s", cache->cid[i]);
  fprintf( stdout,"\n");
}

void print_allcache( cachelist_param_t *cachelist)
{
  cache_param_t *ptr;

  fprintf( stdout,"cache list\n");
  
  ptr = cachelist->first;
  while( ptr != NULL){
    print_cache( ptr);
    ptr=ptr->next;
  }
}
