//
//   Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
//
//   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 version 2 for more details.
//
//   You should have received a copy of the GNU General Public License
//   version 2 along with this program; if not, write to the
//   Free Software Foundation, Inc.,
//   51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
//

#ifndef MEMORY_H
#define MEMORY_H

#include "mem/cartridge.h"
#include "interrupter.h"
#include "pakinfo.h"
#include "sound.h"
#include "tima.h"
#include "video.h"

namespace gambatte {

class File;
class FilterInfo;
class InputGetter;

class Memory {
public:
	explicit Memory(Interrupter const&);
	bool loaded() const;
	char const * romTitle() const;
	PakInfo const pakInfo(bool) const;
	void setStatePtrs(SaveState&);
	unsigned long saveState(SaveState&, unsigned long);
	void loadState(SaveState const&);
	void loadSavedata();
	void saveSavedata();
	std::string const saveBasePath() const;
	void setOsdElement(transfer_ptr<OsdElement>);

	unsigned long stop(unsigned long, bool&);
	bool isCgb() const;
	bool ime() const;
	bool halted() const;
	unsigned long nextEventTime() const;
	bool isActive() const;
	long cyclesSinceBlit(unsigned long) const;

	void freeze(unsigned long);
	bool halt(unsigned long);
	void ei(unsigned long);
	void di();
	unsigned pendingIrqs(unsigned long);
	void ackIrq(unsigned, unsigned long);

	unsigned ff_read(unsigned, unsigned long);
	unsigned read(unsigned, unsigned long);
	void write(unsigned, unsigned, unsigned long);
	void ff_write(unsigned, unsigned, unsigned long);

	unsigned long event(unsigned long);
	unsigned long resetCounters(unsigned long);
	LoadRes loadROM(File&, std::string const&, bool, bool);
	void setSaveDir(std::string const&);
	void setInputGetter(InputGetter*);
	void setEndtime(unsigned long, unsigned long);
	void setSoundBuffer(uint_least32_t*);
	std::size_t fillSoundBuffer(unsigned long);

	void setVideoBuffer(uint_least32_t*, std::ptrdiff_t);
	void setCgbColorCorrection(int);
	void setDmgPaletteColor(int, int, unsigned long);

	void setGameGenie(std::string const&);
	void setGameShark(std::string const&);
	void updateInput();

private:
	Cartridge cart_;
	unsigned char ioamhram_[0x200];
	InputGetter *getInput_;
	unsigned long lastOamDmaUpdate_;
	InterruptRequester intreq_;
	Tima tima_;
	LCD lcd_;
	PSG psg_;
	Interrupter interrupter_;
	unsigned short dmaSource_;
	unsigned short dmaDestination_;
	unsigned char oamDmaPos_;
	unsigned char oamDmaStartPos_;
	unsigned char serialCnt_;
	bool blanklcd_;
	enum HdmaState { hdma_low, hdma_high, hdma_requested } haltHdmaState_;

	void decEventCycles(IntEventId, unsigned long);
	void oamDmaInitSetup();
	void updateOamDma(unsigned long);
	void startOamDma(unsigned long);
	void endOamDma(unsigned long);
	unsigned char const * oamDmaSrcPtr() const;
	unsigned long dma(unsigned long);
	unsigned nontrivial_ff_read(unsigned, unsigned long);
	unsigned nontrivial_read(unsigned, unsigned long);
	void nontrivial_ff_write(unsigned, unsigned, unsigned long);
	void nontrivial_write(unsigned, unsigned, unsigned long);
	void updateSerial(unsigned long);
	void updateTimaIrq(unsigned long);
	void updateIrqs(unsigned long);
	bool isDoubleSpeed() const;
};

}

#endif
