namespace spark
{
	namespace buffers
	{
		template <typename A>
		struct disk_t : base_t<A>
		{
			spark_require_simplex(A);

			disk_t();
			disk_t(common::string_t filename);
			disk_t(const disk_t<A>& that);
			disk_t(disk_t<A>&& that);
			~disk_t();

			disk_t<A>& operator =(disk_t<A> that);
			flag operator ==(const disk_t<A>& that) const;
			flag operator !=(const disk_t<A>& that) const;
			pointers::releasing_t<disk_t<A>> operator &();

			virtual unit length() const;
			virtual flag peeker(unit cursor, A& value) const;
			virtual flag reader(unit& cursor, A& value) const;
			virtual none vacate();
			virtual flag writer(unit& cursor, A value);

			private:

			pointers::referring_t<disk_t<A>> pointer;
			common::string_t filename;
			common::file_t file;
		};
	}

	namespace buffers
	{
		template <typename A>
		disk_t<A>::disk_t() : disk_t<A>(U"")
		{

		}

		template <typename A>
		disk_t<A>::disk_t(common::string_t filename)
		{
			self.pointer = pointers::referring_t<disk_t<A>>();
			self.filename = pass(filename);
			self.file = common::file_t();

			if (self.filename != U"")
			{
				if (self.file = common::file_t(self.filename, U"rb+"))
				{
					return;
				}

				if (self.file = common::file_t(self.filename, U"wb+"))
				{
					return;
				}
			}
		}

		template <typename A>
		disk_t<A>::disk_t(const disk_t<A>& that)
		{
			self.pointer = pointers::referring_t<disk_t<A>>();
			self.filename = that.filename;
			self.file = that.file;
		}

		template <typename A>
		disk_t<A>::disk_t(disk_t<A>&& that) : disk_t<A>()
		{
			swap(self.pointer, that.pointer);
			swap(self.filename, that.filename);
			swap(self.file, that.file);
		}

		template <typename A>
		disk_t<A>::~disk_t()
		{

		}

		template <typename A>
		disk_t<A>& disk_t<A>::operator =(disk_t<A> that)
		{
			swap(self, that);

			return self;
		}

		template <typename A>
		flag disk_t<A>::operator ==(const disk_t<A>& that) const
		{
			if (self.filename != that.filename)
			{
				return false;
			}

			if (self.file != that.file)
			{
				return false;
			}

			return true;
		}

		template <typename A>
		flag disk_t<A>::operator !=(const disk_t<A>& that) const
		{
			return !(self == that);
		}

		template <typename A>
		pointers::releasing_t<disk_t<A>> disk_t<A>::operator &()
		{
			if (!self.pointer)
			{
				self.pointer = pointers::referring_t<disk_t<A>>(self);
			}

			return self.pointer;
		}

		template <typename A>
		unit disk_t<A>::length() const
		{
			unit result;

			if (self.file.seek_end(0_u))
			{
				if (self.file.tell(result))
				{
					return result;
				}
			}

			return 0_u;
		}

		template <typename A>
		flag disk_t<A>::peeker(unit cursor, A& value) const
		{
			if (self.file.seek_set(cursor))
			{
				if (self.file.read(value))
				{
					return true;
				}
			}

			return false;
		}

		template <typename A>
		flag disk_t<A>::reader(unit& cursor, A& value) const
		{
			if (self.file.seek_set(cursor))
			{
				if (self.file.read(value))
				{
					cursor += common::size<A>::bytes();

					return true;
				}
			}

			return false;
		}

		template <typename A>
		none disk_t<A>::vacate()
		{
			self.file = common::file_t(self.filename, U"wb+");
		}

		template <typename A>
		flag disk_t<A>::writer(unit& cursor, A value)
		{
			if (self.file.seek_set(cursor))
			{
				if (self.file.write(value))
				{
					cursor += common::size<A>::bytes();

					return true;
				}
			}

			return false;
		}
	}
}

#endif
