// Copyright (c) 2012 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.

#ifndef PPAPI_SHARED_IMPL_VAR_H_
#define PPAPI_SHARED_IMPL_VAR_H_

#include <string>

#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/shared_impl/host_resource.h"
#include "ppapi/shared_impl/ppapi_shared_export.h"

namespace ppapi {

class ArrayBufferVar;
class ArrayVar;
class DictionaryVar;
class NPObjectVar;
class ProxyObjectVar;
class ResourceVar;
class StringVar;
class VarTracker;

// Var -------------------------------------------------------------------------

// Represents a non-POD var.
class PPAPI_SHARED_EXPORT Var : public base::RefCounted<Var> {
 public:
  // Returns a string representing the given var for logging purposes.
  static std::string PPVarToLogString(PP_Var var);

  virtual StringVar* AsStringVar();
  virtual ArrayBufferVar* AsArrayBufferVar();
  virtual NPObjectVar* AsNPObjectVar();
  virtual ProxyObjectVar* AsProxyObjectVar();
  virtual ArrayVar* AsArrayVar();
  virtual DictionaryVar* AsDictionaryVar();
  virtual ResourceVar* AsResourceVar();

  // Creates a PP_Var corresponding to this object. The return value will have
  // one reference addrefed on behalf of the caller.
  PP_Var GetPPVar();

  // Returns the type of this var.
  virtual PP_VarType GetType() const = 0;

  // Returns the ID corresponing to the string or object if it exists already,
  // or 0 if an ID hasn't been generated for this object (the plugin is holding
  // no refs).
  //
  // Contrast to GetOrCreateVarID which creates the ID and a ref on behalf of
  // the plugin.
  int32 GetExistingVarID() const;

 protected:
  friend class base::RefCounted<Var>;
  friend class VarTracker;

  Var();
  virtual ~Var();

  // Returns the unique ID associated with this string or object, creating it
  // if necessary. The return value will be 0 if the string or object is
  // invalid.
  //
  // This function will take a reference to the var that will be passed to the
  // caller.
  int32 GetOrCreateVarID();

  // Sets the internal object ID. This assumes that the ID hasn't been set
  // before. This is used in cases where the ID is generated externally.
  void AssignVarID(int32 id);

  // Reset the assigned object ID.
  void ResetVarID() { var_id_ = 0; }

 private:
  // This will be 0 if no ID has been assigned (this happens lazily).
  int32 var_id_;

  DISALLOW_COPY_AND_ASSIGN(Var);
};

// StringVar -------------------------------------------------------------------

// Represents a string-based Var.
//
// Returning a given string as a PP_Var:
//   return StringVar::StringToPPVar(my_string);
//
// Converting a PP_Var to a string:
//   StringVar* string = StringVar::FromPPVar(var);
//   if (!string)
//     return false;  // Not a string or an invalid var.
//   DoSomethingWithTheString(string->value());
class PPAPI_SHARED_EXPORT StringVar : public Var {
 public:
  explicit StringVar(const std::string& str);
  StringVar(const char* str, uint32 len);
  virtual ~StringVar();

  const std::string& value() const { return value_; }
  // Return a pointer to the internal string. This allows other objects to
  // temporarily store a weak pointer to our internal string. Use with care; the
  // pointer *will* become invalid if this StringVar is removed from the
  // tracker. (All of this applies to value(), but this one's even easier to use
  // dangerously).
  const std::string* ptr() const { return &value_; }

  // Var override.
  virtual StringVar* AsStringVar() OVERRIDE;
  virtual PP_VarType GetType() const OVERRIDE;

  // Helper function to create a PP_Var of type string that contains a copy of
  // the given string. The input data must be valid UTF-8 encoded text, if it
  // is not valid UTF-8, a NULL var will be returned.
  //
  // The return value will have a reference count of 1. Internally, this will
  // create a StringVar and return the reference to it in the var.
  static PP_Var StringToPPVar(const std::string& str);
  static PP_Var StringToPPVar(const char* str, uint32 len);

  // Same as StringToPPVar but avoids a copy by destructively swapping the
  // given string into the newly created StringVar. The string must already be
  // valid UTF-8. After the call, *src will be empty.
  static PP_Var SwapValidatedUTF8StringIntoPPVar(std::string* src);

  // Helper function that converts a PP_Var to a string. This will return NULL
  // if the PP_Var is not of string type or the string is invalid.
  static StringVar* FromPPVar(PP_Var var);

 private:
  StringVar();  // Makes an empty string.

  std::string value_;

  DISALLOW_COPY_AND_ASSIGN(StringVar);
};

// ArrayBufferVar --------------------------------------------------------------

// Represents an array buffer Var.
//
// Note this is an abstract class. To create an appropriate concrete one, you
// need to use the VarTracker:
//   VarArrayBuffer* buf =
//       PpapiGlobals::Get()->GetVarTracker()->CreateArrayBuffer(size);
//
// Converting a PP_Var to an ArrayBufferVar:
//   ArrayBufferVar* array = ArrayBufferVar::FromPPVar(var);
//   if (!array)
//     return false;  // Not an ArrayBuffer or an invalid var.
//   DoSomethingWithTheBuffer(array);
class PPAPI_SHARED_EXPORT ArrayBufferVar : public Var {
 public:
  ArrayBufferVar();
  virtual ~ArrayBufferVar();

  virtual void* Map() = 0;
  virtual void Unmap() = 0;
  virtual uint32 ByteLength() = 0;

  // Creates a new shared memory region, and copies the data in the
  // ArrayBufferVar into it. On the plugin side, host_shm_handle_id will be set
  // to some value that is not -1. On the host side, plugin_shm_handle will be
  // set to a valid SharedMemoryHandle.
  //
  // Returns true if creating the shared memory (and copying) is successful,
  // false otherwise.
  virtual bool CopyToNewShmem(PP_Instance instance,
                              int* host_shm_handle_id,
                              base::SharedMemoryHandle* plugin_shm_handle) = 0;

  // Var override.
  virtual ArrayBufferVar* AsArrayBufferVar() OVERRIDE;
  virtual PP_VarType GetType() const OVERRIDE;

  // Helper function that converts a PP_Var to an ArrayBufferVar. This will
  // return NULL if the PP_Var is not of ArrayBuffer type.
  static ArrayBufferVar* FromPPVar(PP_Var var);

 private:
  DISALLOW_COPY_AND_ASSIGN(ArrayBufferVar);
};

}  // namespace ppapi

#endif  // PPAPI_SHARED_IMPL_VAR_H_