/*
------------------------------------------------------------------------------
denef - Decode NEF image files
Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org)

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------
*/

#include <stdlib.h>
#include <math.h>
#include <iostream.h>
#include <fstream.h>

#include <map>
#include <vector>
#include <string>

#include <unistd.h>
#include <getopt.h>

#include "metacam.h"
#include "nefdata.h"

static const char *rcsid="$Id: nefdata.cc,v 1.3 2000/09/18 07:51:43 daniel Exp $";

static void
Process_IFD(const IFD &ifd, tagmap &tag_map)
{
    for (int i=0; i<ifd.Entries(); ++i) {
	const IFDEntry &e = ifd[i];
	    idpair id(e.Tag(), e.Type());
	    tag_map[id] = new IFDEntry(e);
    }
}

static void
Clear_Tag_Map(tagmap &tag_map)
{
    tagmap::iterator iter;
    for (iter = tag_map.begin(); iter != tag_map.end(); ++iter) {
	if ((*iter).second) {
	    delete (*iter).second;
	    (*iter).second = 0;
	}
    }
    tag_map.clear();
}


extern nefImageData *
Load_NEF_Data(istream &is)
{
    tiffFile tiff(is, 0);
    tagmap tag_map;

    tiffUNSIGNED nef_ifd_start = 0;

    // Get IFD0
    IFD ifd = tiff.Get_IFD();
    Process_IFD(ifd, tag_map);
    ifd = ifd.Next_IFD();

    // Look for NEF ifd
    idpair nef_id(0x014a, 4);
    tagmap::iterator iter = tag_map.find(nef_id);
    if (iter != tag_map.end() && ((*iter).second)) {
	vector<unsigned long> uv = (*iter).second->Get_UVALUES();
	nef_ifd_start = uv[0];
	delete (*iter).second;
	(*iter).second = 0;
    }

    Clear_Tag_Map(tag_map);
    if (!nef_ifd_start) {
	cerr << "Couldn't locate NEF IFD" << endl;
	return 0;
    }

    IFD exif = tiff.Get_IFD(nef_ifd_start);
    Process_IFD(exif, tag_map);
	    
    idpair stripoffsets_id(0x0111, 4);
    idpair stripcounts_id(0x0117, 4);

    bool got_data = true;

    vector<tiffUNSIGNED> stripoffsets;
    vector<tiffUNSIGNED> stripcounts;

    iter = tag_map.find(stripoffsets_id);
    if (iter != tag_map.end() && ((*iter).second)) {
	stripoffsets = (*iter).second->Get_UVALUES();
    } else {
	got_data = false;
    }

    iter = tag_map.find(stripcounts_id);
    if (iter != tag_map.end() && ((*iter).second)) {
	stripcounts = (*iter).second->Get_UVALUES();
    } else {
	got_data = false;
    }

    if (!got_data) {
	cerr << "Couldn't locate NEF Data" << endl;
	Clear_Tag_Map(tag_map);
	return 0;
    }

    unsigned long width=0;
    unsigned long height=0;

    iter = tag_map.find(idpair(256,4));
    if (iter != tag_map.end() && ((*iter).second)) {
	width = (*iter).second->Get_UVALUES()[0];
    } else {
	iter = tag_map.find(idpair(256,3));
	if (iter != tag_map.end() && ((*iter).second)) {
	    width = (*iter).second->Get_UVALUES()[0];
	}
    }
    
    iter = tag_map.find(idpair(257,4));
    if (iter != tag_map.end() && ((*iter).second)) {
	height = (*iter).second->Get_UVALUES()[0];
    } else {
	tagmap::iterator iter = tag_map.find(idpair(257,3));
	if (iter != tag_map.end() && ((*iter).second)) {
	    height = (*iter).second->Get_UVALUES()[0];
	}
    }

    nefImageData *nef = new nefImageData(width, height);
    
    short *s = nef->Data();
    
    for (unsigned int i=0; i<stripoffsets.size(); ++i) {
	unsigned long offset = stripoffsets[i];
	unsigned long bcount = stripcounts[i];
		    
	unsigned char *buf = new unsigned char[bcount];
	unsigned char *obuf = new unsigned char[bcount * 2];

	is.seekg(offset);
	is.read(buf, bcount);

	// Now - have to convert this 12 bit data to 16 bits

	unsigned long ofs = 0;
	int col=0;
	while (ofs < bcount) {
	    long val;
	    if (col & 1) {
		val = buf[ofs];
		val = (val << 8) | buf[++ofs];
		val = val & 0x000fff;
		++ofs;
	    } else {
		val = buf[ofs];
		val = (val << 8) | buf[++ofs];
		val = val >> 4;
	    }

	    // Now, val is a 12 bit number.. We'll multiply it by 2, so that
	    // some divide by 2's later don't drop any data

	    (*s++) = val*2;
	    ++col;
	}
		    
	delete [] buf;
	delete [] obuf;
    }

    Clear_Tag_Map(tag_map);

    return nef;
}

extern nefImageData *
Test_NEF_Data()
{
    int width=100;
    int height=100;

    nefImageData *nef = new nefImageData(width, height);


    short *s = nef->Data();
    for (int y=0; y<height; ++y) {
	for (int x=0; x<width; ++x) {
	    if ((x == 50) || (x==49)) {
		*(s++) = 0;
	    } else {
		if (!((x^y) & 1)) {
		    *(s++) = x;
		} else {
		    *(s++) = y;
		}
	    }
	}
    }
    
    return nef;
}


