/*

  xmunipack - fits image bitmap

  Copyright © 2018 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack 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 3 of the License, or
  (at your option) any later version.

  Munipack 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 Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/


#include "fits.h"
#include <cfloat>
#include <wx/wx.h>
#include <algorithm>

#ifdef __WXDEBUG__
#include <wx/debug.h>
#include <wx/txtstrm.h>
#include <wx/wfstream.h>
#endif



using namespace std;


// ---  FitsBitmap

// A simple, thread safe, replacement for wxImage.
// Memory should be managed via malloc/free functions.

class FitsBitmapData: public wxObjectRefData
{
public:
  FitsBitmapData();
  FitsBitmapData(int, int, unsigned char *);
  virtual ~FitsBitmapData();

  int width, height;
  unsigned char *rgb;
};


FitsBitmapData::FitsBitmapData(): width(0),height(0),rgb(0) {}

FitsBitmapData::FitsBitmapData(int w, int h, unsigned char *d):
  width(w),height(h),rgb(d) {}


FitsBitmapData::~FitsBitmapData()
{
  free(rgb);
}


FitsBitmap::FitsBitmap() {}

FitsBitmap::FitsBitmap(int w,int h, unsigned char *d)
{
  wxASSERT(w > 0 && h > 0 && d);
  UnRef();
  SetRefData(new FitsBitmapData(w,h,d));
}

FitsBitmap::FitsBitmap(const FitsBitmap& bitmap)
{
  int width = bitmap.GetWidth();
  int height = bitmap.GetHeight();
  int n = 3*width*height;
  unsigned char *rgb = (unsigned char *) malloc(n);
  const unsigned char *old = bitmap.GetRGB();
  copy(old,old+n,rgb);
  SetRefData(new FitsBitmapData(width,height,rgb));
}

FitsBitmap& FitsBitmap::operator= (const FitsBitmap& bitmap)
{
  if( this != &bitmap ) {
    if( bitmap.IsOk() ) {
      int width = bitmap.GetWidth();
      int height = bitmap.GetHeight();
      int n = 3*width*height;
      unsigned char *rgb = (unsigned char *) malloc(n);
      const unsigned char *old = bitmap.GetRGB();
      copy(old,old+n,rgb);
      UnRef();
      SetRefData(new FitsBitmapData(width,height,rgb));
    }
  }
  return *this;
}

FitsBitmap::~FitsBitmap()
{
  UnRef();
}

int FitsBitmap::GetWidth() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  if( data )
    return data->width;
  else
    return 0;
}

int FitsBitmap::GetHeight() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  if( data )
    return data->height;
  else
    return 0;
}

const unsigned char *FitsBitmap::GetRGB() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  if( data )
    return data->rgb;
  else
    return 0;
}

unsigned char *FitsBitmap::NewRGB() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  if( data ) {
    int npix = 3*data->width*data->height;
    unsigned char *rgb = (unsigned char *) malloc(npix);
    memcpy(rgb,data->rgb,npix);
    return rgb;
  }
  else
    return 0;
}

unsigned char *FitsBitmap::NewTopsyTurvyRGB() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  if( data ) {
    int npix = 3*data->width;
    unsigned char *rgb = (unsigned char *) malloc(npix*data->height);
    for(int i = 0; i < data->height; i++)
      memcpy(rgb+i*npix,data->rgb+(data->height - i - 1)*npix,npix);
    return rgb;
  }
  else
    return 0;
}

bool FitsBitmap::IsOk() const
{
  FitsBitmapData *data = static_cast<FitsBitmapData *>(m_refData);
  return data && data->width > 0 && data->height > 0 && data->rgb;
}
