/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License, Version 2.0 
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License. 
 */

#include "avro_private.h"
#include "avro/errors.h"
#include <limits.h>
#include <errno.h>
#include <string.h>
#include "schema.h"
#include "datum.h"
#include "st.h"

struct validate_st {
	avro_schema_t expected_schema;
	int rval;
};

static int
schema_map_validate_foreach(char *key, avro_datum_t datum,
			    struct validate_st *vst)
{
	AVRO_UNUSED(key);

	if (!avro_schema_datum_validate(vst->expected_schema, datum)) {
		vst->rval = 0;
		return ST_STOP;
	}
	return ST_CONTINUE;
}

int
avro_schema_datum_validate(avro_schema_t expected_schema, avro_datum_t datum)
{
	check_param(EINVAL, expected_schema, "expected schema");
	check_param(EINVAL, is_avro_datum(datum), "datum");

	int rval;
	long i;

	switch (avro_typeof(expected_schema)) {
	case AVRO_NULL:
		return is_avro_null(datum);

	case AVRO_BOOLEAN:
		return is_avro_boolean(datum);

	case AVRO_STRING:
		return is_avro_string(datum);

	case AVRO_BYTES:
		return is_avro_bytes(datum);

	case AVRO_INT32:
		return is_avro_int32(datum)
		    || (is_avro_int64(datum)
			&& (INT_MIN <= avro_datum_to_int64(datum)->i64
			    && avro_datum_to_int64(datum)->i64 <= INT_MAX));

	case AVRO_INT64:
		return is_avro_int32(datum) || is_avro_int64(datum);

	case AVRO_FLOAT:
		return is_avro_int32(datum) || is_avro_int64(datum)
		    || is_avro_float(datum);

	case AVRO_DOUBLE:
		return is_avro_int32(datum) || is_avro_int64(datum)
		    || is_avro_float(datum) || is_avro_double(datum);

	case AVRO_FIXED:
		return (is_avro_fixed(datum)
			&& (avro_schema_to_fixed(expected_schema)->size ==
			    avro_datum_to_fixed(datum)->size));

	case AVRO_ENUM:
		if (is_avro_enum(datum)) {
			long value = avro_datum_to_enum(datum)->value;
			long max_value =
			    avro_schema_to_enum(expected_schema)->symbols->
			    num_entries;
			return 0 <= value && value <= max_value;
		}
		return 0;

	case AVRO_ARRAY:
		if (is_avro_array(datum)) {
			struct avro_array_datum_t *array =
			    avro_datum_to_array(datum);

			for (i = 0; i < array->els->num_entries; i++) {
				union {
					st_data_t data;
					avro_datum_t datum;
				} val;
				st_lookup(array->els, i, &val.data);
				if (!avro_schema_datum_validate
				    ((avro_schema_to_array
				      (expected_schema))->items, val.datum)) {
					return 0;
				}
			}
			return 1;
		}
		return 0;

	case AVRO_MAP:
		if (is_avro_map(datum)) {
			struct validate_st vst =
			    { avro_schema_to_map(expected_schema)->values, 1
			};
			st_foreach(avro_datum_to_map(datum)->map,
				   HASH_FUNCTION_CAST schema_map_validate_foreach,
				   (st_data_t) & vst);
			return vst.rval;
		}
		break;

	case AVRO_UNION:
		if (is_avro_union(datum)) {
			struct avro_union_schema_t *union_schema =
			    avro_schema_to_union(expected_schema);
			struct avro_union_datum_t *union_datum =
			    avro_datum_to_union(datum);
			union {
				st_data_t data;
				avro_schema_t schema;
			} val;

			if (!st_lookup
			    (union_schema->branches, union_datum->discriminant,
			     &val.data)) {
				return 0;
			}
			return avro_schema_datum_validate(val.schema,
							  union_datum->value);
		}
		break;

	case AVRO_RECORD:
		if (is_avro_record(datum)) {
			struct avro_record_schema_t *record_schema =
			    avro_schema_to_record(expected_schema);
			for (i = 0; i < record_schema->fields->num_entries; i++) {
				avro_datum_t field_datum;
				union {
					st_data_t data;
					struct avro_record_field_t *field;
				} val;
				st_lookup(record_schema->fields, i, &val.data);

				rval =
				    avro_record_get(datum, val.field->name,
						    &field_datum);
				if (rval) {
					/*
					 * TODO: check for default values 
					 */
					return rval;
				}
				if (!avro_schema_datum_validate
				    (val.field->type, field_datum)) {
					return 0;
				}
			}
			return 1;
		}
		break;

	case AVRO_LINK:
		{
			return
			    avro_schema_datum_validate((avro_schema_to_link
							(expected_schema))->to,
						       datum);
		}
		break;
	}
	return 0;
}
