#include "FractoriumPch.h"
#include "FractoriumSettings.h"

/// <summary>
/// Constructor that passes the parent to the base and sets up reasonable defaults
/// if the settings file was not present or corrupted.
/// </summary>
FractoriumSettings::FractoriumSettings()
#ifdef _WIN32
	: QSettings(QSettings::IniFormat, QSettings::UserScope, "Fractorium", "Fractorium", nullptr)
#else
	: QSettings(QSettings::IniFormat, QSettings::UserScope, "fractorium", "fractorium", nullptr)
#endif
{
	EnsureDefaults();
}

/// <summary>
/// Make sure options have reasonable values in them first.
/// </summary>
void FractoriumSettings::EnsureDefaults()
{
	auto info = OpenCLInfo::Instance();

	if (FinalQuality() == 0)
		FinalQuality(1000);

	if (FinalTemporalSamples() == 0)
		FinalTemporalSamples(100);

	if (FinalSupersample() == 0)
		FinalSupersample(2);

	if (FinalStrips() == 0)
		FinalStrips(1);

	if (XmlTemporalSamples() == 0)
		XmlTemporalSamples(100);

	if (XmlQuality() == 0)
		XmlQuality(1000);

	if (XmlSupersample() == 0)
		XmlSupersample(2);

	if (Devices().empty() && !info->Devices().empty())
		Devices(QList<QVariant> { 0 });

	if (ThreadCount() == 0 || ThreadCount() > Timing::ProcessorCount())
		ThreadCount(std::max(1u, Timing::ProcessorCount() - 1));//Default to one less to keep the UI responsive for first time users.

	if (FinalThreadCount() == 0 || FinalThreadCount() > Timing::ProcessorCount())
		FinalThreadCount(Timing::ProcessorCount());

	FinalThreadPriority(Clamp<int>(FinalThreadPriority(), static_cast<int>(eThreadPriority::LOWEST), static_cast<int>(eThreadPriority::HIGHEST)));
	CpuSubBatch(std::max(1u, CpuSubBatch()));
	OpenCLSubBatch(std::max(1u, OpenCLSubBatch()));

	if (OpenCLSubBatchPct() == 0)
		OpenCLSubBatchPct(0.025);//Default to 256 iters per thread when using the default sub batch size of 10,240.

	OpenCLSubBatchPct(Clamp(OpenCLSubBatchPct(), 0.01, 1.0));

	if (FinalOpenCLSubBatchPct() == 0)
		FinalOpenCLSubBatchPct(0.025);//Default to 256 iters per thread when using the default sub batch size of 10,240.

	FinalOpenCLSubBatchPct(Clamp(FinalOpenCLSubBatchPct(), 0.01, 1.0));
	RandomCount(std::max(1u, RandomCount()));

	if (CpuQuality() == 0)
		CpuQuality(10);

	if (OpenClQuality() == 0)
		OpenClQuality(30);

	if (FinalScale() > static_cast<int>(eScaleType::SCALE_HEIGHT))
		FinalScale(0);

	if (OpenXmlExt() == "")
		OpenXmlExt("*.flame");

	if (SaveXmlExt() == "")
		SaveXmlExt(".flame");

	if (OpenImageExt() == "")
		OpenImageExt("*.png");

	if (SaveImageExt() == "")
#ifndef __APPLE__
		SaveImageExt(".png");

#else
		SaveImageExt("Png (*.png)");
#endif

	if (FinalExt() != "jpg" && FinalExt() != "png" && FinalExt() != "exr"
#ifdef _WIN32
			&& FinalExt() != "bmp"
#endif
	   )
		FinalExt("png");

	if (AnimationFps() == 0)
		AnimationFps(30);

	auto s = OpenFolder();
	QDir dir(s);

	if (s.isEmpty() || !dir.exists())
	{
		QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation);

		if (!paths.empty())
			OpenFolder(paths[0]);
	}

	s = SaveFolder();
	dir = QDir(s);

	if (s.isEmpty() || !dir.exists())
	{
		QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation);

		if (!paths.empty())
			SaveFolder(paths[0]);
	}

	if (OpenPaletteImageFolder() == "")
		OpenPaletteImageFolder(QCoreApplication::applicationDirPath());

	if (value(SHAREDTEXTURE).toString() == "")//Set this to true if the setting is missing because it only needs to be false for the rare system that has problems with shared textures.
		SharedTexture(true);

	Compat::m_Compat = Flam3Compat();
}

/// <summary>
/// Interactive renderer settings.
/// </summary>

bool FractoriumSettings::EarlyClip()							 { return value(EARLYCLIP).toBool();                                       }
void FractoriumSettings::EarlyClip(bool b)						 { setValue(EARLYCLIP, b);                                                 }

bool FractoriumSettings::YAxisUp()								 { return value(YAXISUP).toBool();		                                   }
void FractoriumSettings::YAxisUp(bool b)						 { setValue(YAXISUP, b);				                                   }

bool FractoriumSettings::Transparency()							 { return value(TRANSPARENCY).toBool();                                    }
void FractoriumSettings::Transparency(bool b)					 { setValue(TRANSPARENCY, b);                                              }

bool FractoriumSettings::OpenCL()								 { return value(OPENCL).toBool();                                          }
void FractoriumSettings::OpenCL(bool b)							 { setValue(OPENCL, b);                                                    }

bool FractoriumSettings::SharedTexture()						 { return value(SHAREDTEXTURE).toBool();                                   }
void FractoriumSettings::SharedTexture(bool b)					 { setValue(SHAREDTEXTURE, b);                                             }

bool FractoriumSettings::Double()								 { return value(DOUBLEPRECISION).toBool();                                 }
void FractoriumSettings::Double(bool b)							 { setValue(DOUBLEPRECISION, b);		                                   }

bool FractoriumSettings::ShowAllXforms()						 { return value(SHOWALLXFORMS).toBool();                                   }
void FractoriumSettings::ShowAllXforms(bool b)					 { setValue(SHOWALLXFORMS, b);			                                   }

bool FractoriumSettings::ShowXforms()                            { return value(SHOWXFORMS, QVariant::fromValue(true)).toBool();           }
void FractoriumSettings::ShowXforms(bool b)                      { setValue(SHOWXFORMS, b);                                                }

bool FractoriumSettings::ShowGrid()                              { return value(SHOWGRID, QVariant::fromValue(true)).toBool();             }
void FractoriumSettings::ShowGrid(bool b)                        { setValue(SHOWGRID, b);                                                  }

bool FractoriumSettings::ToggleType()                            { return value(TOGGLETYPE).toBool();                                      }
void FractoriumSettings::ToggleType(bool b)                      { setValue(TOGGLETYPE, b);                                                }

bool FractoriumSettings::Png16Bit()                              { return value(PNG16BIT).toBool();                                        }
void FractoriumSettings::Png16Bit(bool b)                        { setValue(PNG16BIT, b);                                                  }

bool FractoriumSettings::ContinuousUpdate()						 { return value(CONTUPDATE).toBool();	                                   }
void FractoriumSettings::ContinuousUpdate(bool b)				 { setValue(CONTUPDATE, b);				                                   }

QList<QVariant> FractoriumSettings::Devices()					 { return value(DEVICES).toList();		                                   }
void FractoriumSettings::Devices(const QList<QVariant>& devices) { setValue(DEVICES, devices);			                                   }

uint FractoriumSettings::ThreadCount()							 { return value(THREADCOUNT).toUInt();                                     }
void FractoriumSettings::ThreadCount(uint i)					 { setValue(THREADCOUNT, i);                                               }

bool FractoriumSettings::CpuDEFilter()							 { return value(CPUDEFILTER).toBool();                                     }
void FractoriumSettings::CpuDEFilter(bool b)					 { setValue(CPUDEFILTER, b);                                               }

bool FractoriumSettings::OpenCLDEFilter()						 { return value(OPENCLDEFILTER).toBool();                                  }
void FractoriumSettings::OpenCLDEFilter(bool b)					 { setValue(OPENCLDEFILTER, b);                                            }

uint FractoriumSettings::CpuSubBatch()							 { return value(CPUSUBBATCH).toUInt();	                                   }
void FractoriumSettings::CpuSubBatch(uint i)					 { setValue(CPUSUBBATCH, i);			                                   }

double FractoriumSettings::OpenCLSubBatchPct()					 { return value(OPENCLSUBBATCHPCT).toDouble();                             }
void FractoriumSettings::OpenCLSubBatchPct(double d)			 { setValue(OPENCLSUBBATCHPCT, d);			                               }

uint FractoriumSettings::OpenCLSubBatch()						 { return value(OPENCLSUBBATCH).toUInt();                                  }
void FractoriumSettings::OpenCLSubBatch(uint i)					 { setValue(OPENCLSUBBATCH, i);			                                   }

uint FractoriumSettings::RandomCount()							 { return value(RANDOMCOUNT).toUInt();	                                   }
void FractoriumSettings::RandomCount(uint i)					 { setValue(RANDOMCOUNT, i);			                                   }

uint FractoriumSettings::CpuQuality()                            { return value(CPUQUALITY).toUInt();                                      }
void FractoriumSettings::CpuQuality(uint i)                      { setValue(CPUQUALITY, i);                                                }

uint FractoriumSettings::OpenClQuality()                         { return value(OPENCLQUALITY).toUInt();                                   }
void FractoriumSettings::OpenClQuality(uint i)                   { setValue(OPENCLQUALITY, i);                                             }

bool FractoriumSettings::LoadLast()                              { return value(LOADLAST).toBool();                                        }
void FractoriumSettings::LoadLast(bool b)                        { setValue(LOADLAST, b);                                                  }

bool FractoriumSettings::RotateAndScale()                        { return value(ROTSCALE).toBool();                                        }
void FractoriumSettings::RotateAndScale(bool b)                  { setValue(ROTSCALE, b);                                                  }

bool FractoriumSettings::Flam3Compat()                           { return value(FLAM3COMPAT, true).toBool();                               }
void FractoriumSettings::Flam3Compat(bool b)                     { setValue(FLAM3COMPAT, b);                                               }

/// <summary>
/// Sequence generation settings.
/// </summary>

double FractoriumSettings::Stagger()                  { return value(STAGGER).toDouble();            }
void FractoriumSettings::Stagger(double d)            { setValue(STAGGER, d);                        }

double FractoriumSettings::StaggerMax()               { return value(STAGGERMAX).toDouble();         }
void FractoriumSettings::StaggerMax(double d)         { setValue(STAGGERMAX, d);                     }

uint FractoriumSettings::FramesPerRot()               { return value(FRAMESPERROT).toUInt();         }
void FractoriumSettings::FramesPerRot(uint i)         { setValue(FRAMESPERROT, i);                   }

uint FractoriumSettings::FramesPerRotMax()            { return value(FRAMESPERROTMAX).toUInt();      }
void FractoriumSettings::FramesPerRotMax(uint i)      { setValue(FRAMESPERROTMAX, i);                }

uint FractoriumSettings::Rotations()                  { return value(ROTATIONS).toDouble();          }
void FractoriumSettings::Rotations(double d)          { setValue(ROTATIONS, d);                      }

uint FractoriumSettings::RotationsMax()               { return value(ROTATIONSMAX).toDouble();       }
void FractoriumSettings::RotationsMax(double d)       { setValue(ROTATIONSMAX, d);                   }

uint FractoriumSettings::BlendFrames()                { return value(BLENDFRAMES).toUInt();          }
void FractoriumSettings::BlendFrames(uint i)          { setValue(BLENDFRAMES, i);                    }

uint FractoriumSettings::BlendFramesMax()             { return value(BLENDFRAMESMAX).toUInt();       }
void FractoriumSettings::BlendFramesMax(uint i)       { setValue(BLENDFRAMESMAX, i);                 }

uint FractoriumSettings::RotationsPerBlend()          { return value(ROTATIONSPERBLEND).toUInt();    }
void FractoriumSettings::RotationsPerBlend(uint i)    { setValue(ROTATIONSPERBLEND, i);              }

uint FractoriumSettings::RotationsPerBlendMax()       { return value(ROTATIONSPERBLENDMAX).toUInt(); }
void FractoriumSettings::RotationsPerBlendMax(uint i) { setValue(ROTATIONSPERBLENDMAX, i);           }

bool FractoriumSettings::Linear()                     { return value(LINEAR).toBool();               }
void FractoriumSettings::Linear(bool b)               { setValue(LINEAR, b);                         }

uint FractoriumSettings::AnimationFps()               { return value(ANIMATION_FPS).toUInt();        }
void FractoriumSettings::AnimationFps(uint i)         { setValue(ANIMATION_FPS, i);                  }

/// <summary>
/// Variations filter settings.
/// </summary>

int  FractoriumSettings::VarFilterSum()           { return value(VARFILTERSUM).toInt();      }
void FractoriumSettings::VarFilterSum(int i)      { setValue(VARFILTERSUM, i);               }

int  FractoriumSettings::VarFilterAssign()        { return value(VARFILTERASSIGN).toInt();   }
void FractoriumSettings::VarFilterAssign(int i)   { setValue(VARFILTERASSIGN, i);            }

int  FractoriumSettings::VarFilterPpsum()         { return value(VARFILTERPPSUM).toInt();    }
void FractoriumSettings::VarFilterPpsum(int i)    { setValue(VARFILTERPPSUM, i);             }

int  FractoriumSettings::VarFilterPpassign()      { return value(VARFILTERPPASSIGN).toInt(); }
void FractoriumSettings::VarFilterPpassign(int i) { setValue(VARFILTERPPASSIGN, i);          }

int  FractoriumSettings::VarFilterSdc()           { return value(VARFILTERSDC).toInt();      }
void FractoriumSettings::VarFilterSdc(int i)      { setValue(VARFILTERSDC, i);               }

int  FractoriumSettings::VarFilterState()         { return value(VARFILTERSTATE).toInt();    }
void FractoriumSettings::VarFilterState(int i)    { setValue(VARFILTERSTATE, i);             }

int  FractoriumSettings::VarFilterParam()         { return value(VARFILTERPARAM).toInt();    }
void FractoriumSettings::VarFilterParam(int i)    { setValue(VARFILTERPARAM, i);             }

int  FractoriumSettings::VarFilterNonparam()      { return value(VARFILTERNONPARAM).toInt(); }
void FractoriumSettings::VarFilterNonparam(int i) { setValue(VARFILTERNONPARAM, i);          }

/// <summary>
/// Final render settings.
/// </summary>

bool FractoriumSettings::FinalEarlyClip()							  { return value(FINALEARLYCLIP).toBool();           }
void FractoriumSettings::FinalEarlyClip(bool b)						  { setValue(FINALEARLYCLIP, b);                     }

bool FractoriumSettings::FinalYAxisUp()								  { return value(FINALYAXISUP).toBool();		     }
void FractoriumSettings::FinalYAxisUp(bool b)						  { setValue(FINALYAXISUP, b);					     }

bool FractoriumSettings::FinalTransparency()						  { return value(FINALTRANSPARENCY).toBool();        }
void FractoriumSettings::FinalTransparency(bool b)					  { setValue(FINALTRANSPARENCY, b);                  }

bool FractoriumSettings::FinalOpenCL()								  { return value(FINALOPENCL).toBool();              }
void FractoriumSettings::FinalOpenCL(bool b)						  { setValue(FINALOPENCL, b);                        }

bool FractoriumSettings::FinalDouble()								  { return value(FINALDOUBLEPRECISION).toBool();     }
void FractoriumSettings::FinalDouble(bool b)						  { setValue(FINALDOUBLEPRECISION, b);			     }

bool FractoriumSettings::FinalSaveXml()								  { return value(FINALSAVEXML).toBool();		     }
void FractoriumSettings::FinalSaveXml(bool b)						  { setValue(FINALSAVEXML, b);					     }

bool FractoriumSettings::FinalDoAll()								  { return value(FINALDOALL).toBool();		         }
void FractoriumSettings::FinalDoAll(bool b)							  { setValue(FINALDOALL, b);					     }

bool FractoriumSettings::FinalDoSequence()							  { return value(FINALDOSEQUENCE).toBool();	         }
void FractoriumSettings::FinalDoSequence(bool b)					  { setValue(FINALDOSEQUENCE, b);				     }

bool FractoriumSettings::FinalUseNumbers()							  { return value(FINALUSENUMBERS).toBool();			 }
void FractoriumSettings::FinalUseNumbers(bool b)					  { setValue(FINALUSENUMBERS, b);					 }

bool FractoriumSettings::FinalPng16Bit()							  { return value(FINALPNG16BIT).toBool();	         }
void FractoriumSettings::FinalPng16Bit(bool b)			    		  { setValue(FINALPNG16BIT, b);			    	     }

bool FractoriumSettings::FinalKeepAspect()							  { return value(FINALKEEPASPECT).toBool();		     }
void FractoriumSettings::FinalKeepAspect(bool b)					  { setValue(FINALKEEPASPECT, b);				     }

uint FractoriumSettings::FinalScale()								  { return value(FINALSCALE).toUInt();			     }
void FractoriumSettings::FinalScale(uint i)							  { setValue(FINALSCALE, i);					     }

QString FractoriumSettings::FinalExt()								  { return value(FINALEXT).toString();			     }
void FractoriumSettings::FinalExt(const QString& s)					  { setValue(FINALEXT, s);						     }

QList<QVariant> FractoriumSettings::FinalDevices()					  { return value(FINALDEVICES).toList();		     }
void FractoriumSettings::FinalDevices(const QList<QVariant>& devices) { setValue(FINALDEVICES, devices);			     }

uint FractoriumSettings::FinalThreadCount()							  { return value(FINALTHREADCOUNT).toUInt();         }
void FractoriumSettings::FinalThreadCount(uint i)					  { setValue(FINALTHREADCOUNT, i);                   }

int FractoriumSettings::FinalThreadPriority()						  { return value(FINALTHREADPRIORITY).toInt();       }
void FractoriumSettings::FinalThreadPriority(int i)					  { setValue(FINALTHREADPRIORITY, i);			     }

double FractoriumSettings::FinalOpenCLSubBatchPct()                   { return value(FINALOPENCLSUBBATCHPCT).toDouble(); }
void FractoriumSettings::FinalOpenCLSubBatchPct(double d)             { setValue(FINALOPENCLSUBBATCHPCT, d);             }

uint FractoriumSettings::FinalQuality()								  { return value(FINALQUALITY).toUInt();             }
void FractoriumSettings::FinalQuality(uint i)						  { setValue(FINALQUALITY, i);                       }

uint FractoriumSettings::FinalTemporalSamples()						  { return value(FINALTEMPORALSAMPLES).toUInt();     }
void FractoriumSettings::FinalTemporalSamples(uint i)				  { setValue(FINALTEMPORALSAMPLES, i);               }

uint FractoriumSettings::FinalSupersample()							  { return value(FINALSUPERSAMPLE).toUInt();         }
void FractoriumSettings::FinalSupersample(uint i)					  { setValue(FINALSUPERSAMPLE, i);                   }

size_t FractoriumSettings::FinalStrips()							  { return value(FINALSTRIPS).toULongLong();	     }
void FractoriumSettings::FinalStrips(size_t i)                        { setValue(FINALSTRIPS, static_cast<uint>(i));     }

/// <summary>
/// Xml file saving settings.
/// </summary>

uint FractoriumSettings::XmlTemporalSamples()       { return value(XMLTEMPORALSAMPLES).toUInt(); }
void FractoriumSettings::XmlTemporalSamples(uint i) { setValue(XMLTEMPORALSAMPLES, i);           }

uint FractoriumSettings::XmlQuality()               { return value(XMLQUALITY).toUInt();         }
void FractoriumSettings::XmlQuality(uint i)         { setValue(XMLQUALITY, i);                   }

uint FractoriumSettings::XmlSupersample()           { return value(XMLSUPERSAMPLE).toUInt();     }
void FractoriumSettings::XmlSupersample(uint i)     { setValue(XMLSUPERSAMPLE, i);               }

QString FractoriumSettings::Id()                    { return value(IDENTITYID).toString();       }
void FractoriumSettings::Id(const QString& s)       { setValue(IDENTITYID, s);                   }

QString FractoriumSettings::Url()                   { return value(IDENTITYURL).toString();      }
void FractoriumSettings::Url(const QString& s)      { setValue(IDENTITYURL, s);                  }

QString FractoriumSettings::Nick()                  { return value(IDENTITYNICK).toString();     }
void FractoriumSettings::Nick(const QString& s)     { setValue(IDENTITYNICK, s);                 }

/// <summary>
/// General operations settings.
/// </summary>

QString FractoriumSettings::OpenFolder()							  { return value(OPENFOLDER).toString();   }
void FractoriumSettings::OpenFolder(const QString& s)				  { setValue(OPENFOLDER, s);			   }

QString FractoriumSettings::OpenPaletteImageFolder()				  { return value(OPENPALETTEIMAGEFOLDER).toString();   }
void FractoriumSettings::OpenPaletteImageFolder(const QString& s)	  { setValue(OPENPALETTEIMAGEFOLDER, s);			   }

QString FractoriumSettings::SaveFolder()							  { return value(SAVEFOLDER).toString();   }
void FractoriumSettings::SaveFolder(const QString& s)				  { setValue(SAVEFOLDER, s);			   }

QString FractoriumSettings::OpenXmlExt()							  { return value(OPENXMLEXT).toString();   }
void FractoriumSettings::OpenXmlExt(const QString& s)				  { setValue(OPENXMLEXT, s);			   }

QString FractoriumSettings::SaveXmlExt()							  { return value(SAVEXMLEXT).toString();   }
void FractoriumSettings::SaveXmlExt(const QString& s)				  { setValue(SAVEXMLEXT, s);			   }

QString FractoriumSettings::OpenImageExt()							  { return value(OPENIMAGEEXT).toString(); }
void FractoriumSettings::OpenImageExt(const QString& s)				  { setValue(OPENIMAGEEXT, s);			   }

QString FractoriumSettings::SaveImageExt()							  { return value(SAVEIMAGEEXT).toString(); }
void FractoriumSettings::SaveImageExt(const QString& s)				  { setValue(SAVEIMAGEEXT, s);		       }

bool FractoriumSettings::SaveAutoUnique()							  { return value(AUTOUNIQUE).toBool();	   }
void FractoriumSettings::SaveAutoUnique(bool b)						  { setValue(AUTOUNIQUE, b);			   }

QMap<QString, QVariant> FractoriumSettings::Variations()			  { return value(UIVARIATIONS).toMap();	   }
void FractoriumSettings::Variations(const QMap<QString, QVariant>& m) { setValue(UIVARIATIONS, m);			   }

QString FractoriumSettings::Theme()									  { return value(STYLETHEME).toString();   }
void FractoriumSettings::Theme(const QString& s)					  { setValue(STYLETHEME, s);			   }