/**
 * DesfireFile.kt
 *
 * Copyright (C) 2011 Eric Butler
 * Copyright (C) 2019  <seil0@mosad.xyz>
 *
 * Authors:
 * Eric Butler <eric@codebutler.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.codebutler.farebot.card.desfire

import android.os.Parcel
import android.os.Parcelable
import com.codebutler.farebot.card.desfire.DesfireFileSettings.RecordDesfireFileSettings
import org.apache.commons.lang3.ArrayUtils


open class DesfireFile private constructor(val id: Int, private val fileSettings: DesfireFileSettings?, val data: ByteArray) :
    Parcelable {

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(id)
        if (this is InvalidDesfireFile) {
            parcel.writeInt(1)
            parcel.writeString(this.errorMessage)
        } else {
            parcel.writeInt(0)
            parcel.writeParcelable(fileSettings, 0)
            parcel.writeInt(data.size)
            parcel.writeByteArray(data)
        }
    }

    override fun describeContents(): Int {
        return 0
    }

    class RecordDesfireFile(fileId: Int, fileSettings: DesfireFileSettings, fileData: ByteArray) :
        DesfireFile(fileId, fileSettings, fileData) {
        private val records: Array<DesfireRecord?>

        init {

            val settings = fileSettings as RecordDesfireFileSettings

            val records = arrayOfNulls<DesfireRecord>(settings.curRecords)
            for (i in 0 until settings.curRecords) {
                val offset = settings.recordSize * i
                records[i] = DesfireRecord(ArrayUtils.subarray(data, offset, offset + settings.recordSize))
            }
            this.records = records
        }
    }

    class InvalidDesfireFile(fileId: Int, val errorMessage: String?) : DesfireFile(fileId, null, ByteArray(0))

    companion object {

        fun create(fileId: Int, fileSettings: DesfireFileSettings, fileData: ByteArray): DesfireFile {
            return (fileSettings as? RecordDesfireFileSettings)?.let { RecordDesfireFile(fileId, it, fileData) }
                ?: DesfireFile(fileId, fileSettings, fileData)
        }

        @Suppress("unused")
        @JvmField
        val CREATOR: Parcelable.Creator<DesfireFile> = object : Parcelable.Creator<DesfireFile> {
            override fun createFromParcel(source: Parcel): DesfireFile {
                val fileId = source.readInt()

                val isError = source.readInt() == 1

                return if (!isError) {
                    val fileSettings =
                        source.readParcelable<Parcelable>(DesfireFileSettings::class.java.classLoader) as DesfireFileSettings
                    val dataLength = source.readInt()
                    val fileData = ByteArray(dataLength)
                    source.readByteArray(fileData)

                    create(fileId, fileSettings, fileData)
                } else {
                    InvalidDesfireFile(fileId, source.readString())
                }
            }

            override fun newArray(size: Int): Array<DesfireFile?> {
                return arrayOfNulls(size)
            }
        }
    }
}