#![allow(unused_attributes)]

#![cfg_attr(feature = "nightly", feature(custom_derive, custom_attribute, plugin))]
#![cfg_attr(feature = "nightly", plugin(serde_macros, json_str, elastic_types_macros, elastic_date_macros))]

#[cfg_attr(feature = "nightly", allow(plugin_as_library))]
#[macro_use]
extern crate json_str;

#[macro_use]
extern crate maplit;

#[cfg_attr(feature = "nightly", allow(plugin_as_library))]
#[macro_use]
extern crate elastic_date_macros;

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

#[macro_use]
extern crate elastic_types;

pub mod date_fixtures {
	use std::marker::PhantomData;
	use serde;
	use elastic_types::mapping::prelude::*;
	use elastic_types::date::prelude::*;

	//A custom date mapping
	#[derive(Default, Clone, Copy, ElasticDateMapping)]
	pub struct MyDateMapping<T: DateFormat = EpochMillis> {
		phantom: PhantomData<T>
	}
	impl <T: DateFormat> ElasticDateMapping<T> for MyDateMapping<T> {
		fn boost() -> Option<f32> {
			Some(1.01)
		}

		fn index() -> Option<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

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

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

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

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

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

		fn precision_step() -> Option<i32> {
			Some(6)
		}
	}
}

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

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

		fn index() -> Option<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

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

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

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

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

		fn fielddata() -> Option<FieldData> {
			Some(FieldData::Disabled)
		}

		fn fields() -> Option<BTreeMap<&'static str, ElasticStringField>> {
			let mut fields = BTreeMap::new();

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

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

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

			Some(fields)
		}

		fn ignore_above() -> Option<usize> {
			Some(50)
		}

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

		fn norms() -> Option<Norms> {
			Some(Norms::Disabled)
		}

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

		fn position_increment_gap() -> Option<usize> {
			Some(8)
		}

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

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

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

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

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

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

		fn index() -> Option<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		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(Debug, Clone, Default, ElasticIntegerMapping)]
	pub struct MyIntegerMapping;
	impl ElasticIntegerMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

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

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

	#[derive(Debug, Clone, Default, ElasticLongMapping)]
	pub struct MyLongMapping;
	impl ElasticLongMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

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

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

	#[derive(Debug, Clone, Default, ElasticShortMapping)]
	pub struct MyShortMapping;
	impl ElasticShortMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

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

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

	#[derive(Debug, Clone, Default, ElasticByteMapping)]
	pub struct MyByteMapping;
	impl ElasticByteMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

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

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

	#[derive(Debug, Clone, Default, ElasticFloatMapping)]
	pub struct MyFloatMapping;
	impl ElasticFloatMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

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

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

	#[derive(Debug, Clone, Default, ElasticDoubleMapping)]
	pub struct MyDoubleMapping;
	impl ElasticDoubleMapping 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<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		fn precision_step() -> Option<u32> {
			Some(2147483647)
		}

		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, ElasticIpMapping)]
	pub struct MyIpMapping;
	impl ElasticIpMapping for MyIpMapping {
		fn boost() -> Option<f32> {
			Some(1.01)
		}

		fn index() -> Option<IndexAnalysis> {
			Some(IndexAnalysis::No)
		}

		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 std::marker::PhantomData;
	use serde;
	use elastic_types::mapping::prelude::*;
	use elastic_types::geo::point::prelude::*;

	#[derive(Debug, Clone, Default, ElasticGeoPointMapping)]
	pub struct MyGeoPointMapping<T: GeoPointFormat = GeoPointObject> {
		phantom: PhantomData<T>
	}
	impl <T: GeoPointFormat> ElasticGeoPointMapping<T> for MyGeoPointMapping<T> {
		fn geohash() -> Option<bool> {
	        Some(false)
	    }

	    fn geohash_precision() -> Option<u8> {
	        Some(12)
	    }

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

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

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

	    fn precision_step() -> Option<i32> {
	        Some(128)
	    }
	}
}

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

	#[derive(Debug, Clone, Default, ElasticGeoShapeMapping)]
	pub struct MyGeoShapeMapping;
	impl ElasticGeoShapeMapping 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 std::collections::BTreeMap;
	use std::net::Ipv4Addr;
	use serde_json;
	use chrono::{ DateTime, UTC };
	use elastic_types::mapping::prelude::*;
	use elastic_types::date::prelude::*;
	use elastic_types::ip::prelude::*;
	use elastic_types::number::prelude::*;
	use elastic_types::string::prelude::*;
	use elastic_types::boolean::prelude::*;
	use elastic_types::geo::prelude::*;
	use ::date_fixtures::*;
	use ::number_fixtures::*;
	use ::boolean_fixtures::*;
	use ::geo_shape_fixtures::*;
	use ::ip_fixtures::*;

	#[derive(Serialize, Deserialize, ElasticType)]
	#[elastic(ty="my_type", mapping="MyTypeMapping")]
	pub struct MyType {
		pub my_date1: DateTime<UTC>,
		pub my_date2: ElasticDate<DefaultDateFormat>,
		pub my_date3: ElasticDate<EpochMillis, MyDateMapping>,
		pub my_string1: String,
		pub my_string2: ElasticString<DefaultStringMapping>,
		pub my_num1: i32,
		pub my_num2: ElasticInteger<MyIntegerMapping>,
		pub my_bool1: bool,
		pub my_bool2: ElasticBoolean<MyBooleanMapping>,
		pub my_geo: Option<ElasticGeoShape<MyGeoShapeMapping>>,
		pub my_ips: Option<Vec<Ipv4Addr>>,
		pub my_map1: BTreeMap<String, serde_json::Value>,
		pub my_map2: BTreeMap<String, String>,
		pub my_val: serde_json::Value
	}

	#[derive(Default, Clone)]
	pub struct MyTypeMapping;
	impl ElasticObjectMapping for MyTypeMapping {
		fn dynamic() -> Option<Dynamic> {
			Some(Dynamic::True)
		}

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

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

	#[derive(Serialize, ElasticType)]
	pub struct MyOtherType {
		pub my_date: ElasticDate<DefaultDateFormat>,
		#[serde(rename="my_renamed_type")]
		pub my_type: MyType,
		#[serde(skip_serializing)]
		pub ignored: String,
		pub my_num: i32,
		pub my_point: ElasticGeoPoint<DefaultGeoPointFormat>,
		pub my_shape: ElasticGeoShape<DefaultGeoShapeMapping>,
		pub my_ip: ElasticIp<MyIpMapping>,
		pub my_strings: Vec<String>,
		pub my_dates: Vec<ElasticDate<DefaultDateFormat>>,
		pub my_brw_ip: &'static Ipv4Addr,
		pub my_brw_point: &'static ElasticGeoPoint<DefaultGeoPointFormat>
	}

	#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ElasticType)]
	pub struct MyStruct {
		pub id: i32,
		pub title: String,
		pub timestamp: DateTime<UTC>,
		pub geo: GeoLocation
	}

	#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ElasticType)]
	pub struct GeoLocation {
		pub ip: Ipv4Addr
	}
}

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