//  BMP
//  Copyright (C) 2005-2007 BMP development.
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License Version 2
//  as published by the Free Software Foundation.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//  --
//
//  The BMPx project hereby grants permission for non-GPL compatible GStreamer
//  plugins to be used and distributed together with GStreamer and BMPx. This
//  permission is above and beyond the permissions granted by the GPL license
//  BMPx is covered by.

#ifndef BMP_VFS_HH
#define BMP_VFS_HH

#include <iostream>
#include <sstream>
#include <cstring>
#include <glibmm.h>
#include <boost/shared_ptr.hpp>

#include "bmp/types/types-basic.hh"
#include "bmp/types/types-library.hh"

namespace Bmp
{
    namespace VFS
    {
#include "exception.hh"

      EXCEPTION(TransportError)
      EXCEPTION(ContainerError)
      EXCEPTION(ProcessingError)
      EXCEPTION(InvalidFlagsError)

      struct ExportData
      {
        Glib::ustring description;
        std::string   extension;

        ExportData () {};
        ExportData (std::string const& _description, std::string const& _extension)
          : description (_description), extension (_extension) {};
      };

      class Handle
      {
        public:

          Handle () {}
          Handle (Glib::ustring const& location)
            : m_buffer      (0),
              m_buffer_size (0),
              m_uri         (location) {}

          ~Handle ()
          {
            if (m_buffer)
            {
              delete[] m_buffer;
            }
          }

          const unsigned char*
          get_buffer () const
          {
            return m_buffer;
          }

          size_t
          get_buffer_size () const
          {
            return m_buffer_size;
          }

          void
          set_buffer (const unsigned char* data, size_t data_size)
          {
            m_buffer = new unsigned char [data_size];
            m_buffer_size = data_size;
            memcpy (m_buffer, data, data_size);
          }

          Glib::ustring const&
          get_uri () const
          {
            return m_uri;
          }

        private:

          unsigned char     * m_buffer;
          size_t	            m_buffer_size;
          Glib::ustring       m_uri;
      };

      class PluginTransportBase
      {
        public:

          PluginTransportBase () {};
          virtual ~PluginTransportBase () {};

          virtual bool
          can_process	(Glib::ustring const& str) = 0;

          virtual void
          handle_read (Handle & handle) throw (ProcessingError) = 0;
           
          virtual void
          handle_write (Handle const& handle) throw (ProcessingError) = 0;
      };

      class PluginContainerBase
      {
        public:

          PluginContainerBase () {};
          virtual ~PluginContainerBase () {};

          virtual bool
          can_process (Glib::ustring const& str) = 0;

          virtual void
          handle_read (Handle & handle, VUri & list) throw (ProcessingError) = 0;

          virtual void
          handle_write (Handle & handle, TrackV const& list) throw (ProcessingError) = 0;

          virtual bool
          can_write () = 0;

          virtual ExportData const&
          get_export_data () = 0;
      };


      typedef std::map<std::string, PluginContainerBase*> ContainerPlugins;
      typedef std::map<std::string, PluginTransportBase*> TransportPlugins;
      typedef std::vector<ExportData>                     ExportDataList;

      enum ProcessingFlags
      {
        FLAG_ZERO = 0,      // _Don't_ use this
        TRANSPORT = 1 << 0,
        CONTAINER = 1 << 1,
      };

      class VFS
      {
        public:

          VFS ();
          ~VFS ();

          static void
          strv_to_uri_list (VUri & list, char **strv, bool free = false)
          {
            char **p = strv;

            while (*p)
            {
              try{
                list.push_back (Glib::ustring (*p));
                } catch (...) {}
              ++p;
            }

            if (free)
            {
              g_strfreev (strv);
            }
          }

          void
          get_containers (ExportDataList & list);

          bool
          has_container (Glib::ustring const& uri);

          void
          read  (Handle & handle, VUri & list, ProcessingFlags flags = ProcessingFlags(TRANSPORT | CONTAINER));

          void
          read  (Handle & handle, ProcessingFlags flags = ProcessingFlags(TRANSPORT));
                
          void
          write (TrackV const& list, Glib::ustring const& uri, std::string const& container);

        private:

          ContainerPlugins  container_plugins;
          TransportPlugins  transport_plugins;

          bool
          load_plugins_transport (std::string const& entry,
                                  std::string const& type);

          bool
          load_plugins_container (std::string const& entry,
                                  std::string const& type);

      };
    } // class VFS
}// namespace Bmp

#endif //!BMP_VFS_H
