/***************************************************************************
 *   Copyright (C) 2003-2007 by Spiros Georgaras <sng@hellug.gr>           *
 *                                                                         *
 *   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.         *
 ***************************************************************************/
#include "exif.h"
//================================
EXIF::EXIF(QString fName){
	fileName=fName;
	IFDoffset=0;
	subIFDoffset=0;
	numOfEntries=0;
  numOfSunEntries=0;
	isExif=checkExif();
	//getDate(mDate);
}
//================================
EXIF::~EXIF(){
	ff.close();
}
//================================
QString EXIF::getExifDate(int mode){
  if(mode==0) return getDate(mDate);
  return getDate(cDate);
//   if(mode==0) return getDate((quint16) mDate);
//   return getDate((quint16) cDate);
	
}
//================================
bool EXIF::checkExif(void){
  int i,j;
	bool found=FALSE;
	char s[100];
	char expected[6]={'E','x','i','f','\0','\0'};
// 	ff.setName(fileName); old impl
	ff.setFileName(fileName);
//   ff.open(IO_ReadOnly); old impl
  ff.open(QIODevice::ReadOnly);
//	ff.at(0); old impl
	ff.seek(0);
//   for(i=0;i<99;i++) s[i]=(char) ff.getch(); old impl
  for(i=0;i<99;i++) ff.getChar(&s[i]);

	for(i=0;i<93;i++){
		if(s[i]==expected[0]){
      //qWarning("E = %c",s[i]);
	  	for(j=i;j<i+6;j++){
        //qWarning("j = %d, j-i = %d",j,j-i);
        //qWarning("s[j] = %c - expected[j-i] = %c\n",s[j],expected[j-i]);
	      if(s[j]!=expected[j-i])break;
			}
      //qWarning("j = %d (%d)",j,i+6);
			if(j==i+6){
				found=TRUE;
				offset=(quint16)(i+6);
				break;
			}
		}
	if(found) break;
  }
  if(!found){
  	//qWarning("oh no");
		return FALSE;
	}else //qWarning("oh yes");
	if(s[offset]=='I') fileType=QDataStream::LittleEndian;
	else if(s[offset]=='M') fileType=QDataStream::BigEndian;
	else return FALSE;
	ds.setDevice(&ff);
	ds.setByteOrder(fileType);
	getIFDoffset();
	getNumOFIFDEntries();
	return TRUE;
}
//================================
quint32 EXIF::getIFDoffset(void){
//  ff.at(offset+4); old impl
	ff.seek(offset+4);
	ds>>IFDoffset;
//	qWarning("IFD offset = %x",IFDoffset);
	return IFDoffset;
}
//================================
quint16 EXIF::getNumOFIFDEntries(void){
// 	ff.at(offset+IFDoffset); old impl
	ff.seek(offset+IFDoffset);
	ds>>numOfEntries;
//	qWarning("IFD entries = %x",numOfEntries);
	return numOfEntries;
}
//================================
QString EXIF::getDate(qint16 EntryID){
	int i;
	bool found=FALSE;
	quint16 id;
	quint32 of;
	for(i=0;i<numOfEntries;i++){
// 		ff.at(offset+IFDoffset+2+(i*12)); old impl
		ff.seek(offset+IFDoffset+2+(i*12));
		ds >> id;
		if(id==EntryID){
			// found in IFD
			of=offset+IFDoffset+10+(i*12);
			found=TRUE;
			break;
		}
	}
	if(found){
		// read modified date
// 		ff.at(of); old impl
		ff.seek(of);
		ds >> of;
    char s[20];
// 		ff.at(offset+of); old impl
		ff.seek(offset+of);
//     ds.readRawBytes(s,20); old impl
    ds.readRawData(s,20);
//		qWarning("date is %s",s);
    return QString(s);
	}else{
  	// goto subIFD
//		qWarning("checking sub iFD");
		getSubOffset();
		for(i=0;i<numOfSunEntries;i++){
// 			ff.at(offset+subIFDoffset+2+(i*12)); old impl
			ff.seek(offset+subIFDoffset+2+(i*12));
			ds >> id;
//			qWarning("id = %X",id);
			if(id==(quint16) cDate){
				// found in IFD
				of=offset+subIFDoffset+10+(i*12);
// 				ff.at(of);  old impl
				ff.seek(of);
				ds >> of;
				of+=offset;
//				qWarning("Readinf at: %X",of);
// 				ff.at(of); old impl
				ff.seek(of);
		    char s[20];
// 		    ds.readRawBytes(s,20); old impl
		    ds.readRawData(s,20);
//				qWarning("date is %s",s);
		    return QString(s);
			}
		}
	}
	return QString(QString::null);
}
//================================
quint32 EXIF::getSubOffset(void){
	int i;
	quint16 id;
	quint32 of;
	for(i=0;i<numOfEntries;i++){
// 		ff.at(offset+IFDoffset+2+(i*12)); old impl
		ff.seek(offset+IFDoffset+2+(i*12));
		ds >> id;
//		qWarning("id = %X",id);
		if(id==(quint16) subID){
			// found in IFD
			of=offset+IFDoffset+10+(i*12);
// 			ff.at(of); old impl
			ff.seek(of);
			ds >> of;
//			qWarning("sub id offset = %X",of);
			subIFDoffset=of;
			getNumOfSunEntries();
			return of;
		}
	}
	subIFDoffset=0;
	return 0;
}
//================================
quint16 EXIF::getNumOfSunEntries(void){
  quint16 num;
// 	ff.at(offset+subIFDoffset); old impl
	ff.seek(offset+subIFDoffset);
	ds >> num;
//	qWarning("num of sub entries = %X (%d)",num,num);
	numOfSunEntries=num;
	return num;
}

