/***************************************************************************
 *
 * Project:  OpenCPN
 *
 ***************************************************************************
 *   Portions Copyright (C) 2010 by David S. Register                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 ***************************************************************************
 */

/////////////////////////////////////////////////////////////////////////////
// Author:      Robert Roebling
// Copyright:   (c) 1998 Robert Roebling
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _OCPN_REGION_H_
#define _OCPN_REGION_H_

#include <wx/wxprec.h>

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif  // precompiled headers

//#if defined(__WXOSX__)
#define USE_NEW_REGION
//#endif

// ----------------------------------------------------------------------------
// OCPNRegion
// ----------------------------------------------------------------------------

class OCPNRegion : public
#ifdef USE_NEW_REGION
                   wxObject
#else
                   wxRegion
#endif
{
public:
  OCPNRegion() {}

  OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h);
  OCPNRegion(const wxPoint& topLeft, const wxPoint& bottomRight);
  OCPNRegion(const wxRect& rect);
  OCPNRegion(const wxRegion& region);
  OCPNRegion(size_t n, const wxPoint* points, int fillStyle = wxODDEVEN_RULE);

  virtual ~OCPNRegion();

  wxRegion* GetNew_wxRegion() const;

#ifdef USE_NEW_REGION

  // common part of ctors for a rectangle region
  void InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h);

  // operators
  // ---------
  bool operator==(const OCPNRegion& region) const { return ODoIsEqual(region); }
  bool operator!=(const OCPNRegion& region) const { return !(*this == region); }

  bool IsOk() const { return m_refData != NULL; }
  bool Ok() const { return IsOk(); }

  // Get the bounding box
  bool GetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const {
    return ODoGetBox(x, y, w, h);
  }
  wxRect GetBox() const {
    wxCoord x, y, w, h;
    return ODoGetBox(x, y, w, h) ? wxRect(x, y, w, h) : wxRect();
  }

  // Test if the given point or rectangle is inside this region
  wxRegionContain Contains(wxCoord x, wxCoord y) const {
    return ODoContainsPoint(x, y);
  }
  wxRegionContain Contains(const wxPoint& pt) const {
    return ODoContainsPoint(pt.x, pt.y);
  }
  wxRegionContain Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const {
    return ODoContainsRect(wxRect(x, y, w, h));
  }
  wxRegionContain Contains(const wxRect& rect) const {
    return ODoContainsRect(rect);
  }

  // Is region equal (i.e. covers the same area as another one)?
  bool IsEqual(const OCPNRegion& region) const;

  // OCPNRegionBase methods
  virtual void Clear();
  virtual bool IsEmpty() const;
  bool Empty() const { return IsEmpty(); }

public:
  //    OCPNRegion( OGdkRegion *region );

  void* GetRegion() const;

  bool Offset(wxCoord x, wxCoord y) { return ODoOffset(x, y); }
  bool Offset(const wxPoint& pt) { return ODoOffset(pt.x, pt.y); }
  bool Intersect(const OCPNRegion& region) { return ODoIntersect(region); }
  bool Union(const OCPNRegion& region) { return ODoUnionWithRegion(region); }
  bool Union(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
    return ODoUnionWithRect(wxRect(x, y, w, h));
  }
  bool Union(const wxRect& rect) { return ODoUnionWithRect(rect); }
  bool Subtract(const OCPNRegion& region) { return ODoSubtract(region); }

protected:
  // ref counting code
  virtual wxObjectRefData* CreateRefData() const;
  virtual wxObjectRefData* CloneRefData(const wxObjectRefData* data) const;

  // wxRegionBase pure virtuals
  virtual bool ODoIsEqual(const OCPNRegion& region) const;
  virtual bool ODoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const;
  virtual wxRegionContain ODoContainsPoint(wxCoord x, wxCoord y) const;
  virtual wxRegionContain ODoContainsRect(const wxRect& rect) const;

  virtual bool ODoOffset(wxCoord x, wxCoord y);
  virtual bool ODoUnionWithRect(const wxRect& rect);
  virtual bool ODoUnionWithRegion(const OCPNRegion& region);
  virtual bool ODoIntersect(const OCPNRegion& region);
  virtual bool ODoSubtract(const OCPNRegion& region);
  //    virtual bool DoXor(const OCPNRegion& region);

#endif

private:
  DECLARE_DYNAMIC_CLASS(OCPNRegion)
};

// ----------------------------------------------------------------------------
// OCPNRegionIterator: decomposes a region into rectangles
// ----------------------------------------------------------------------------

class OCPNRegionIterator {
public:
  OCPNRegionIterator();
  OCPNRegionIterator(const OCPNRegion& region);
  virtual ~OCPNRegionIterator();

  void Reset();
  void Reset(const OCPNRegion& region);

  bool HaveRects() const;
  void NextRect(void);
  wxRect GetRect() const;

private:
#ifdef USE_NEW_REGION
  void Init();
  void CreateRects(const OCPNRegion& r);

  size_t m_current;
  OCPNRegion m_region;

  wxRect* m_rects;
  size_t m_numRects;
#else
  wxRegionIterator* m_ri;
#endif
};

#endif
// _OCPN_REGION_H_
