#pragma once
#include <fstream>
#include <sstream>
#include <iostream>

namespace SDX
{
/** ファイルの読込書込モード.*/
enum class FileMode
{
	Read,//読込のみ
	Write,//書込のみ
	Add,//書込時、末尾に追加
	None,//開かれていない
};

/** 入出力可能なテキストかバイナリファイルを表すクラス.*/
///	\include FileSample.h
class File
{
private:
	std::ifstream fst;
	bool canRead;
	bool canWrite;
	bool canAdd;
	bool isBinary;
	std::string fileName;
public:
	
	/** ファイル名とモードを指定して、ファイルを開く.*/
	File(const char* ファイル名 , FileMode 読み書きモード , bool バイナリファイル = false )
	{
		File::Open( ファイル名 , 読み書きモード , バイナリファイル );
	}
	
	/** ファイルを開く.*/
	bool Open(const char* ファイル名 , FileMode 読み書きモード , bool バイナリファイル = false )
	{
		std::string mode;
		this->fileName = ファイル名;

		switch(読み書きモード)
		{
			case FileMode::Read:
				if( isBinary )	fst.open( ファイル名 , std::ios::in | std::ios::binary );
				else			fst.open( ファイル名 , std::ios::in );
				canRead = true;
				canWrite = false;
				canAdd = false;
			break;
			case FileMode::Write:
				if( isBinary )	fst.open( ファイル名 , std::ios::out | std::ios::binary );
				else			fst.open( ファイル名 , std::ios::out );
				canWrite = true;
				canRead = false;
				canAdd = false;
			break;
			case FileMode::Add:
				if( isBinary )	fst.open( ファイル名 , std::ios::out | std::ios::app | std::ios::binary );
				else			fst.open( ファイル名 , std::ios::out | std::ios::app );
				canWrite = true;
				canAdd = true;
				canRead = false;
			break;
		}

		this->isBinary = バイナリファイル;

		if ( fst.fail() )
		{
			canRead = false;
			canWrite = false;
			canAdd = false;
		}

		return true;
	}

	/** ファイルを閉じる.*/
	bool Close()
	{
		fst.close();
		canRead = false;
		canWrite = false;
		canAdd = false;
	}
			
	/** ファイルモードを取得.*/
	FileMode GetFileMode()
	{
		if( this->canAdd )  return FileMode::Add;
		if( this->canWrite) return FileMode::Write;
		if( this->canRead ) return FileMode::Read;
		return FileMode::None;
	}

	/** ファイル名を取得.*/
	const char* GetFileName()
	{				
		return this->fileName.c_str();
	}

	/** データを読み込む.*/
	///FileMode::Readの場合成功。
	///読込先変数にデータを読み込む。
	template< class T>
	bool Read(T &読込先変数 )
	{
		if( canRead ) fst << 読込先変数;
		return canRead;
	}
			
	/** データを書き込む.*/
	///FileModeがWriteかAddの場合成功。
	///書込元変数をファイルに書き込む。
	template< class T>
	bool Write(T &書込元変数)
	{
		if( canWrite ) fst >> 書込元変数;
		return canWrite;
	}
			
	/** FileModeがReadの場合Read、WriteかAddの場合Writeを行う.*/
	template< class T>
	bool ReadWrite(T &読み書き変数 )
	{
		if( canRead )
		{
			fst >> buf;
			return true;
		}else if( canWrite ){
			fst << buf;
			return true;
		}		
		return false;
	}
	
	/** ファイルから一行読込.*/
	///FileModeがReadの場合成功。
	bool GetLine(std::string &代入先文字列)
	{
		if (canRead) getline(fst, 代入先文字列);
		return canRead;
	}
			
	/** CSVファイルの一行読込.*/
	///FileModeがReadの場合成功。
	///ファイルから一行読込、カンマ区切りで引数に追加
	bool GetLineCSV(std::vector<std::string> &代入先配列)
	{
		if( canRead )
		{
			std::string str;
			std::string buf;

			getline( fst , str );
			std::istringstream iss( str );

			while( getline( iss , buf , ',' ) )
			{
				代入先配列.push_back(buf);
			}
		}
		return canRead;
	}
	
	/** ファイルの終端判定.*/
	bool CheckEOF()
	{
		return fst.eof();
	}

};
}