/*
 * AXFPtrList.cpp
 */

#include <stdio.h>

#include "AXFPtrList.hpp"

AXFPtrList::AXFPtrList(AXFMutex* listMutexPtr)
    : m_listMutexInited(false),
      m_listMutexPtr(listMutexPtr) {
  if (m_listMutexPtr == NULL) {
    // 通常は m_listMutex を使用する
    m_listMutexPtr = &m_listMutex;

    // (テスト時に外部から listMutexPtr を指定すると、そちらを使用する)
  }
}

AXFPtrList::~AXFPtrList() {
}

int AXFPtrList::init() {
  if (!m_listMutexInited) {
    // リスト排他処理用のMutexクラスを初期化
    if (m_listMutexPtr->init() != AXFMutex::MUTEX_SUCCESS) {
      return PTR_LIST_ERROR;
    }
    m_listMutexInited = true;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::lock() {
  if (m_listMutexPtr->lock() != AXFMutex::MUTEX_SUCCESS) {
    return PTR_LIST_ERROR;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::unlock() {
  if (m_listMutexPtr->unlock() != AXFMutex::MUTEX_SUCCESS) {
    return PTR_LIST_ERROR;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::add(void* ptr, bool onlyOnce) {
  void* args[] = {
    ptr,
    &onlyOnce,
  };

  int ret;
  if ((ret = listWork(listFuncAdd, args)) != PTR_LIST_SUCCESS) {
    return ret;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::del(void* ptr) {
  bool found = false;
  void* args[] = {
    ptr,
    &found,
  };

  int ret;
  if ((ret = listWork(listFuncDel, args)) != PTR_LIST_SUCCESS) {
    return ret;
  }
  if (!found) {
    return PTR_LIST_ERROR_NOT_FOUND;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::delAll() {
  int ret;
  if ((ret = listWork(listFuncDelAll, NULL)) != PTR_LIST_SUCCESS) {
    return ret;
  }
  return PTR_LIST_SUCCESS;
}

int AXFPtrList::listWork(ListFunc func, void **args) {
  // リストをロック
  int ret;
  if ((ret = lock()) != PTR_LIST_SUCCESS) {
    return ret;
  }

  // 引数で指定された func を実行
  (*func)(this, args);

  // リストをアンロック
  if ((ret = unlock()) != PTR_LIST_SUCCESS) {
    return ret;
  }
  return PTR_LIST_SUCCESS;
}

void AXFPtrList::listFuncAdd(AXFPtrList* obj, void** args) {
  void* ptr = args[0];
  bool onlyOnce = *(bool*)args[1];

  if (onlyOnce) {
    AXFPtrList::iterator it = obj->begin();
    while (it != obj->end()) {
      if (*it == ptr) {
	// 既に追加済
	return;
      }
      it++;
    }
  }
  obj->push_back(ptr);
}

void AXFPtrList::listFuncDel(AXFPtrList* obj, void** args) {
  void* ptr = args[0];
  bool* found = (bool*)args[1];

  AXFPtrList::iterator it = obj->begin();
  while (it != obj->end()) {
    if (*it == ptr) {
      *found = true;
      obj->erase(it);
      return;
    }
    it++;
  }
}

void AXFPtrList::listFuncDelAll(AXFPtrList* obj, void** args) {
  obj->clear();
}
