#![feature(proc_macro, plugin, test)]
#![plugin(json_str, elastic_date_macros)]

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate elastic_types_derive;

#[allow(plugin_as_library)]
#[macro_use]
extern crate json_str;

#[macro_use]
extern crate maplit;

extern crate serde;
extern crate serde_json;
pub extern crate chrono;
extern crate geo as georust;
extern crate geojson;
extern crate test;

#[macro_use]
extern crate elastic_types;

pub mod date_fixtures {
	use elastic_types::mapping::prelude::*;
	use elastic_types::date::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyDateMapping;
	impl DateMapping for MyDateMapping {
		type Format = EpochMillis;

		fn null_value() -> Option<Date<Self::Format, Self>> {
			Some(Date::build(2015, 3, 14, 16, 45, 13, 778))
		}

		fn boost() -> Option<f32> 				{ Some(1.01) }

		fn index() -> Option<bool> 				{ Some(true) }

		fn doc_values() -> Option<bool> 		{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }
	}
}

pub mod string_fixtures {
	use std::collections::BTreeMap;
	use elastic_types::mapping::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyTextMapping;
	impl TextMapping for MyTextMapping {
		fn fields() -> Option<BTreeMap<&'static str, ElasticStringField>> {
			let mut fields = BTreeMap::new();

			fields.insert("raw", ElasticStringField::Keyword(
				KeywordFieldMapping {
					analyzer: Some("my_analyzer"),
					..Default::default()
				})
			);

			fields.insert("count", ElasticStringField::TokenCount(
				ElasticTokenCountFieldMapping::default())
			);

			fields.insert("comp", ElasticStringField::Completion(
				ElasticCompletionFieldMapping::default())
			);

			Some(fields)
		}

		fn fielddata_frequency_filter() -> Option<FieldDataFrequencyFilter> { 
			Some(FieldDataFrequencyFilter { min: Some(0.0), ..Default::default() })
		}

		fn analyzer() -> Option<&'static str> 				{ Some("my_analyzer") }

		fn boost() -> Option<f32> 							{ Some(1.3) }

		fn eager_global_ordinals() -> Option<bool> 			{ Some(false) }

		fn fielddata() -> Option<bool> 						{ Some(true) }

		fn include_in_all() -> Option<bool> 				{ Some(true) }

		fn ignore_above() -> Option<u32> 					{ Some(512) }

		fn index() -> Option<bool> 							{ Some(false) }

		fn index_options() -> Option<IndexOptions> 			{ Some(IndexOptions::Freqs) }

		fn norms() -> Option<bool> 							{ Some(true) }

		fn position_increment_gap() -> Option<u32> 			{ Some(1) }

		fn store() -> Option<bool> 							{ Some(true) }

		fn search_analyzer() -> Option<&'static str> 		{ Some("my_analyzer") }

		fn search_quote_analyzer() -> Option<&'static str> 	{ Some("my_analyzer") }

		fn similarity() -> Option<&'static str> 			{ Some("BM25") }

		fn term_vector() -> Option<TermVector> 				{ Some(TermVector::Yes) }
	}

	#[derive(Default, Clone)]
	pub struct MyKeywordMapping;
	impl KeywordMapping for MyKeywordMapping {
		fn fields() -> Option<BTreeMap<&'static str, ElasticStringField>> {
			let mut fields = BTreeMap::new();

			fields.insert("text", ElasticStringField::Text(
				TextFieldMapping {
					analyzer: Some("my_analyzer"),
					..Default::default()
				})
			);

			fields.insert("count", ElasticStringField::TokenCount(
				ElasticTokenCountFieldMapping::default())
			);

			fields.insert("comp", ElasticStringField::Completion(
				ElasticCompletionFieldMapping::default())
			);

			Some(fields)
		}

		fn analyzer() -> Option<&'static str> 			{ Some("my_analyzer") }

		fn boost() -> Option<f32> 						{ Some(1.03) }

		fn doc_values() -> Option<bool> 				{ Some(true) }

		fn eager_global_ordinals() -> Option<bool> 		{ Some(false) }

		fn include_in_all() -> Option<bool> 			{ Some(false) }

		fn ignore_above() -> Option<u32> 				{ Some(256) }

		fn index() -> Option<bool> 						{ Some(true) }

		fn index_options() -> Option<IndexOptions> 		{ Some(IndexOptions::Docs) }

		fn norms() -> Option<bool> 						{ Some(false) }

		fn null_value() -> Option<&'static str> 		{ Some("my string") }

		fn store() -> Option<bool> 						{ Some(false) }

		fn search_analyzer() -> Option<&'static str> 	{ Some("my_analyzer") }

		fn similarity() -> Option<&'static str> 		{ Some("classic") }
	}
}

pub mod boolean_fixtures {
	use elastic_types::mapping::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyBooleanMapping;
	impl BooleanMapping for MyBooleanMapping {
		fn boost() -> Option<f32> 			{ Some(1.01) }

		fn index() -> Option<bool> 			{ Some(false) }

		fn doc_values() -> Option<bool> 	{ Some(true) }

		fn store() -> Option<bool> 			{ Some(true) }

		fn null_value() -> Option<bool> 	{ Some(false) }
	}
}

pub mod number_fixtures {
	use elastic_types::mapping::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyIntegerMapping;
	impl IntegerMapping for MyIntegerMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<i32> 			{ Some(42) }
	}

	#[derive(Default, Clone)]
	pub struct MyLongMapping;
	impl LongMapping for MyLongMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<i64> 			{ Some(-42) }
	}

	#[derive(Default, Clone)]
	pub struct MyShortMapping;
	impl ShortMapping for MyShortMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<i16> 			{ Some(42) }
	}

	#[derive(Default, Clone)]
	pub struct MyByteMapping;
	impl ByteMapping for MyByteMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<i8> 			{ Some(1) }
	}

	#[derive(Default, Clone)]
	pub struct MyFloatMapping;
	impl FloatMapping for MyFloatMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<f32> 			{ Some(1.04) }
	}

	#[derive(Default, Clone)]
	pub struct MyDoubleMapping;
	impl DoubleMapping for MyDoubleMapping {
		fn coerce() -> Option<bool> 			{ Some(true) }

		fn boost() -> Option<f32> 				{ Some(1.1) }

		fn doc_values() -> Option<bool> 		{ Some(false) }

		fn ignore_malformed() -> Option<bool> 	{ Some(true) }

		fn include_in_all() -> Option<bool> 	{ Some(true) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<f64> 			{ Some(-0.00002) }
	}
}

pub mod ip_fixtures {
	use std::net::Ipv4Addr;
	use elastic_types::mapping::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyIpMapping;
	impl IpMapping for MyIpMapping {
		fn boost() -> Option<f32> 				{ Some(1.01) }

		fn index() -> Option<bool> 				{ Some(false) }

		fn doc_values() -> Option<bool> 		{ Some(true) }

		fn store() -> Option<bool> 				{ Some(true) }

		fn null_value() -> Option<Ipv4Addr> 	{ Some(Ipv4Addr::new(127, 0, 0, 1)) }	
	}
}

pub mod geo_point_fixtures {
	use elastic_types::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyGeoPointMapping;
	impl GeoPointMapping for MyGeoPointMapping {
		type Format = GeoPointArray;

		fn geohash() -> Option<bool> 				{ Some(false) }

		fn geohash_precision() -> Option<Distance> 	{ Some(Distance(50.0, DistanceUnit::Meters)) }

		fn geohash_prefix() -> Option<bool> 		{ Some(true) }

		fn ignore_malformed() -> Option<bool> 		{ Some(true) }

		fn lat_lon() -> Option<bool> 				{ Some(true) }
	}
}

pub mod geo_shape_fixtures {
	use elastic_types::mapping::prelude::*;

	#[derive(Default, Clone)]
	pub struct MyGeoShapeMapping;
	impl GeoShapeMapping for MyGeoShapeMapping {
		fn tree() -> Option<Tree> 					{ Some(Tree::Geohash) }

		fn precision() -> Option<Distance> 			{ Some(Distance(50.0, DistanceUnit::Meters)) }

		fn tree_levels() -> Option<i32> 			{ Some(8) }

		fn strategy() -> Option<Strategy> 			{ Some(Strategy::Recursive) }

		fn distance_error_pct() -> Option<f32> 		{ Some(0.5) }

		fn orientation() -> Option<Orientation> 	{ Some(Orientation::Clockwise) }

		fn points_only() -> Option<bool> 			{ Some(false) }
	}
}

pub mod object_fixtures {
	use serde;
	use chrono::{ DateTime, UTC };
	use elastic_types::prelude::*;

	#[derive(Default, Clone)]
	pub struct MySmlMapping;
	impl ObjectMapping for MySmlMapping {
		fn name() -> &'static str { "ty" }
	}
	impl PropertiesMapping for MySmlMapping {
		fn props_len() -> usize { 3 }
		
		fn serialize_props<S>(serializer: &mut S, state: &mut S::StructState) -> Result<(), S::Error>
		where S: serde::Serializer {
			try!(field_ser(serializer, state, "integer", i32::mapping()));
			try!(field_ser(serializer, state, "string", String::mapping()));
			try!(field_ser(serializer, state, "date", DateTime::<UTC>::mapping()));

			Ok(())
		}
	}

	#[derive(Default, Clone)]
	pub struct MyMedMapping;
	impl ObjectMapping for MyMedMapping {
		fn name() -> &'static str { "ty" }
	}
	impl PropertiesMapping for MyMedMapping {
		fn props_len() -> usize { 4 }
		
		fn serialize_props<S>(serializer: &mut S, state: &mut S::StructState) -> Result<(), S::Error>
		where S: serde::Serializer {
			try!(field_ser(serializer, state, "integer", i32::mapping()));
			try!(field_ser(serializer, state, "string", String::mapping()));
			try!(field_ser(serializer, state, "date", DateTime::<UTC>::mapping()));
			try!(field_ser(serializer, state, "field", MySmlMapping));

			Ok(())
		}
	}

	#[derive(Default, Clone)]
	pub struct MyLrgMapping;
	impl ObjectMapping for MyLrgMapping {
		fn name() -> &'static str { "ty" }
	}
	impl PropertiesMapping for MyLrgMapping {
		fn props_len() -> usize { 4 }
		
		fn serialize_props<S>(serializer: &mut S, state: &mut S::StructState) -> Result<(), S::Error>
		where S: serde::Serializer {
			try!(field_ser(serializer, state, "integer", i32::mapping()));
			try!(field_ser(serializer, state, "string", String::mapping()));
			try!(field_ser(serializer, state, "date", DateTime::<UTC>::mapping()));
			try!(field_ser(serializer, state, "field", MyMedMapping));

			Ok(())
		}
	}
}

pub mod object;
pub mod geo_point;
pub mod geo_shape;
pub mod date;
pub mod string;
pub mod number;
pub mod boolean;
pub mod template;