/*
 * 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.
 */

package hessian

import (
	"reflect"
	"time"
)

import (
	perrors "github.com/pkg/errors"
)

// ///////////////////////////////////////
// Date
// ///////////////////////////////////////
var ZeroDate = time.Time{}

// # time in UTC encoded as 64-bit long milliseconds since epoch
// ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
// ::= x4b b3 b2 b1 b0       # minutes since epoch
func encDateInMs(b []byte, i interface{}) []byte {
	value := UnpackPtrValue(reflect.ValueOf(i))
	vi := value.Interface().(time.Time)
	if vi.Equal(ZeroDate) {
		return append(b, BC_NULL)
	}
	b = append(b, BC_DATE)
	return append(b, PackInt64(vi.UnixMilli())...)
}

func encDateInMinute(b []byte, v time.Time) []byte {
	b = append(b, BC_DATE_MINUTE)
	return append(b, PackInt32(int32(v.Unix()/60))...)
}

/////////////////////////////////////////
// Date
/////////////////////////////////////////

// # time in UTC encoded as 64-bit long milliseconds since epoch
// ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
// ::= x4b b3 b2 b1 b0       # minutes since epoch
func (d *Decoder) decDate(flag int32) (time.Time, error) {
	var (
		err error
		l   int
		tag byte
		buf [8]byte
		s   []byte
		i64 int64
		t   time.Time
	)

	if flag != TAG_READ {
		tag = byte(flag)
	} else {
		tag, _ = d.ReadByte()
	}

	switch tag {
	case BC_NULL:
		return ZeroDate, nil
	case BC_DATE: //'d': //date
		s = buf[:8]
		l, err = d.nextFull(s)
		if err != nil {
			return t, err
		}
		if l != 8 {
			return t, ErrNotEnoughBuf
		}
		i64 = UnpackInt64(s)
		return time.Unix(i64/1000, i64%1000*10e5), nil
		// return time.Unix(i64/1000, i64*100), nil

	case BC_DATE_MINUTE:
		s = buf[:4]
		l, err = d.nextFull(s)
		if err != nil {
			return t, err
		}
		if l != 4 {
			return t, ErrNotEnoughBuf
		}
		i64 = int64(UnpackInt32(s))
		return time.Unix(i64*60, 0), nil

	default:
		return t, perrors.Errorf("decDate Invalid type: %v", tag)
	}
}
