#!/usr/bin/env python3
"""
SPOS - Small Payload Object Serializer
Copyright (C) 2020 Luiz Eduardo Amaral <luizamaral306@gmail.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/>.
"""
import argparse
import json
import sys

from spos import encode, decode


def _encode(infile, outfile, _payload_spec, format):
    payload_data = json.load(infile)
    infile.close()

    payload_spec = json.load(_payload_spec)
    _payload_spec.close()

    message = encode(payload_data, payload_spec, format)
    message = message if format == "bytes" else bytes(message, encoding="ascii")
    if outfile.name == "<stdout>":
        sys.stdout.buffer.write(message)
    else:
        outfile.write(message)
    outfile.close()


def _decode(infile, outfile, _payload_spec, format):
    if infile.name == "<stdin>":
        message = sys.stdin.buffer.read()
    else:
        message = infile.read()
        infile.close()

    payload_spec = json.load(_payload_spec)
    _payload_spec.close()

    message = f"0x{message.decode('ascii')}" if format == "hex" else message
    message = f"0b{message.decode('ascii')}" if format == "bin" else message

    payload_data, meta = decode(message, payload_spec)
    outfile.write(json.dumps({"meta": meta, "body": payload_data}, indent=2))
    outfile.close()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Spos is a tool for serializing objects."
    )
    parser.add_argument(
        "-d", "--decode", action="store_true", help="decodes a message."
    )
    parser.add_argument(
        "-p",
        "--payload-spec",
        type=argparse.FileType("r"),
        required=True,
        help="json file payload specifications.",
    )
    parser.add_argument(
        "-f",
        "--format",
        choices=["bin", "hex", "bytes"],
        default="bytes",
        help="Output format",
    )
    parser.add_argument(
        "infile",
        nargs="?",
        type=argparse.FileType("rb"),
        default=sys.stdin,
        help="Input file",
    )
    parser.add_argument(
        "outfile",
        nargs="?",
        type=argparse.FileType("wb"),
        default=sys.stdout,
        help="Output file",
    )
    args = parser.parse_args()
    if args.decode:
        _decode(args.infile, args.outfile, args.payload_spec, args.format)
    else:
        _encode(args.infile, args.outfile, args.payload_spec, args.format)
