/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <log4cxx/logstring.h>
#if !defined(LOG4CXX)
#define LOG4CXX 1
#endif
#include <log4cxx/helpers/aprinitializer.h>
#include <apr_pools.h>
#include <apr_atomic.h>
#include <assert.h>
#include <log4cxx/helpers/threadspecificdata.h>
#include <apr_thread_mutex.h>
#include <apr_thread_proc.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/helpers/filewatchdog.h>

using namespace log4cxx::helpers;
using namespace log4cxx;

bool APRInitializer::isDestructed = false;


namespace {
 	extern "C" void tlsDestruct(void* ptr) {
  		delete ((ThreadSpecificData*) ptr);
	}
}

APRInitializer::APRInitializer() : p(0), mutex(0), startTime(0), tlsKey(0) {
    apr_initialize();
    apr_pool_create(&p, NULL);
    apr_atomic_init(p);
    startTime = apr_time_now();
#if APR_HAS_THREADS
    apr_status_t stat = apr_threadkey_private_create(&tlsKey, tlsDestruct, p);
    assert(stat == APR_SUCCESS);
    stat = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, p);
    assert(stat == APR_SUCCESS);
#endif
}

APRInitializer::~APRInitializer() {
    {
#if APR_HAS_THREADS
        synchronized sync(mutex);
        apr_threadkey_private_delete(tlsKey);
#endif
        for(std::list<FileWatchdog*>::iterator iter = watchdogs.begin();
            iter != watchdogs.end();
            iter++) {
            delete *iter;
        }
    }

// TODO LOGCXX-322
#ifndef APR_HAS_THREADS
	apr_terminate();
#endif
    isDestructed = true;
}

APRInitializer& APRInitializer::getInstance() {
  static APRInitializer init;
  return init;
}


log4cxx_time_t APRInitializer::initialize() {
  return getInstance().startTime;
}

apr_pool_t* APRInitializer::getRootPool() {
  return getInstance().p;
}

apr_threadkey_t* APRInitializer::getTlsKey() {
   return getInstance().tlsKey;
}

void APRInitializer::registerCleanup(FileWatchdog* watchdog) {
    APRInitializer& instance(getInstance());
#if APR_HAS_THREADS
    synchronized sync(instance.mutex);
#endif
    instance.watchdogs.push_back(watchdog);
}

void APRInitializer::unregisterCleanup(FileWatchdog* watchdog) {
    APRInitializer& instance(getInstance());
#if APR_HAS_THREADS
    synchronized sync(instance.mutex);
#endif
    for(std::list<FileWatchdog*>::iterator iter = instance.watchdogs.begin();
        iter != instance.watchdogs.end();
        iter++) {
		if(*iter == watchdog)
		{
			instance.watchdogs.erase(iter);
			return;
		}
    }
}

