// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ipc/ipc_message_utils.h"

#include "base/json/json_writer.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/values.h"

namespace IPC {

const int kMaxRecursionDepth = 100;

// Value serialization

static bool ReadValue(const Message* m, void** iter, Value** value,
                      int recursion);

static void WriteValue(Message* m, const Value* value, int recursion) {
  if (recursion > kMaxRecursionDepth) {
    LOG(WARNING) << "Max recursion depth hit in WriteValue.";
    return;
  }

  m->WriteInt(value->GetType());

  switch (value->GetType()) {
    case Value::TYPE_NULL:
    break;
    case Value::TYPE_BOOLEAN: {
      bool val;
      value->GetAsBoolean(&val);
      WriteParam(m, val);
      break;
    }
    case Value::TYPE_INTEGER: {
      int val;
      value->GetAsInteger(&val);
      WriteParam(m, val);
      break;
    }
    case Value::TYPE_REAL: {
      double val;
      value->GetAsReal(&val);
      WriteParam(m, val);
      break;
    }
    case Value::TYPE_STRING: {
      std::string val;
      value->GetAsString(&val);
      WriteParam(m, val);
      break;
    }
    case Value::TYPE_BINARY: {
      const BinaryValue* binary = static_cast<const BinaryValue*>(value);
      m->WriteData(binary->GetBuffer(), binary->GetSize());
      break;
    }
    case Value::TYPE_DICTIONARY: {
      const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);

      WriteParam(m, static_cast<int>(dict->size()));

      for (DictionaryValue::key_iterator it = dict->begin_keys();
           it != dict->end_keys(); ++it) {
        Value* subval;
        if (dict->GetWithoutPathExpansion(*it, &subval)) {
          WriteParam(m, *it);
          WriteValue(m, subval, recursion + 1);
        } else {
          NOTREACHED() << "DictionaryValue iterators are filthy liars.";
        }
      }
      break;
    }
    case Value::TYPE_LIST: {
      const ListValue* list = static_cast<const ListValue*>(value);
      WriteParam(m, static_cast<int>(list->GetSize()));
      for (size_t i = 0; i < list->GetSize(); ++i) {
        Value* subval;
        if (list->Get(i, &subval)) {
          WriteValue(m, subval, recursion + 1);
        } else {
          NOTREACHED() << "ListValue::GetSize is a filthy liar.";
        }
      }
      break;
    }
  }
}

// Helper for ReadValue that reads a DictionaryValue into a pre-allocated
// object.
static bool ReadDictionaryValue(const Message* m, void** iter,
                                DictionaryValue* value, int recursion) {
  int size;
  if (!ReadParam(m, iter, &size))
    return false;

  for (int i = 0; i < size; ++i) {
    std::wstring key;
    Value* subval;
    if (!ReadParam(m, iter, &key) ||
        !ReadValue(m, iter, &subval, recursion + 1))
      return false;
    value->Set(key, subval);
  }

  return true;
}

// Helper for ReadValue that reads a ReadListValue into a pre-allocated
// object.
static bool ReadListValue(const Message* m, void** iter,
                          ListValue* value, int recursion) {
  int size;
  if (!ReadParam(m, iter, &size))
    return false;

  for (int i = 0; i < size; ++i) {
    Value* subval;
    if (!ReadValue(m, iter, &subval, recursion + 1))
      return false;
    value->Set(i, subval);
  }

  return true;
}

static bool ReadValue(const Message* m, void** iter, Value** value,
                      int recursion) {
  if (recursion > kMaxRecursionDepth) {
    LOG(WARNING) << "Max recursion depth hit in ReadValue.";
    return false;
  }

  int type;
  if (!ReadParam(m, iter, &type))
    return false;

  switch (type) {
    case Value::TYPE_NULL:
    *value = Value::CreateNullValue();
    break;
    case Value::TYPE_BOOLEAN: {
      bool val;
      if (!ReadParam(m, iter, &val))
        return false;
      *value = Value::CreateBooleanValue(val);
      break;
    }
    case Value::TYPE_INTEGER: {
      int val;
      if (!ReadParam(m, iter, &val))
        return false;
      *value = Value::CreateIntegerValue(val);
      break;
    }
    case Value::TYPE_REAL: {
      double val;
      if (!ReadParam(m, iter, &val))
        return false;
      *value = Value::CreateRealValue(val);
      break;
    }
    case Value::TYPE_STRING: {
      std::string val;
      if (!ReadParam(m, iter, &val))
        return false;
      *value = Value::CreateStringValue(val);
      break;
    }
    case Value::TYPE_BINARY: {
      const char* data;
      int length;
      if (!m->ReadData(iter, &data, &length))
        return false;
      *value = BinaryValue::CreateWithCopiedBuffer(data, length);
      break;
    }
    case Value::TYPE_DICTIONARY: {
      scoped_ptr<DictionaryValue> val(new DictionaryValue());
      if (!ReadDictionaryValue(m, iter, val.get(), recursion))
        return false;
      *value = val.release();
      break;
    }
    case Value::TYPE_LIST: {
      scoped_ptr<ListValue> val(new ListValue());
      if (!ReadListValue(m, iter, val.get(), recursion))
        return false;
      *value = val.release();
      break;
    }
    default:
    return false;
  }

  return true;
}

void ParamTraits<DictionaryValue>::Write(Message* m, const param_type& p) {
  WriteValue(m, &p, 0);
}

bool ParamTraits<DictionaryValue>::Read(
    const Message* m, void** iter, param_type* r) {
  int type;
  if (!ReadParam(m, iter, &type) || type != Value::TYPE_DICTIONARY)
    return false;

  return ReadDictionaryValue(m, iter, r, 0);
}

void ParamTraits<DictionaryValue>::Log(const param_type& p, std::wstring* l) {
  std::string json;
  base::JSONWriter::Write(&p, false, &json);
  l->append(UTF8ToWide(json));
}

void ParamTraits<ListValue>::Write(Message* m, const param_type& p) {
  WriteValue(m, &p, 0);
}

bool ParamTraits<ListValue>::Read(
    const Message* m, void** iter, param_type* r) {
  int type;
  if (!ReadParam(m, iter, &type) || type != Value::TYPE_LIST)
    return false;

  return ReadListValue(m, iter, r, 0);
}

void ParamTraits<ListValue>::Log(const param_type& p, std::wstring* l) {
  std::string json;
  base::JSONWriter::Write(&p, false, &json);
  l->append(UTF8ToWide(json));
}
}  // namespace IPC
