package com.jscape.inet.sftp.protocol.v4.messages;

import com.jscape.util.Clock;
import com.jscape.util.file.PosixFilePermissions;
import com.jscape.util.file.UnixFileType;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * @author Alex Usun
 */
public class FileAttributes {

    public static final long TIME_FACTOR = 1000L;

    public final int type;
    public final Long size;
    public final String owner;
    public final String group;
    public final PosixFilePermissions permissions;
    public final Long accessTime;
    public final Integer accessTimeNanos;
    public final Long createTime;
    public final Integer createTimeNanos;
    public final Long modificationTime;
    public final Integer modificationTimeNanos;
    public final Acl[] acls;
    public final Map<String, String> extendedData;

    public static FileAttributes empty() {
        return new FileAttributes(FileType.SSH_FILEXFER_TYPE_UNKNOWN, null, null, null, null, null, null, null, null, new HashMap<String, String>());
    }

    public static FileAttributes attributesFor(long lastModificationDate) {
        return new FileAttributes(FileType.SSH_FILEXFER_TYPE_UNKNOWN, null, null, null, null, null, null, lastModificationDate / TIME_FACTOR, null, new HashMap<String, String>());
    }

    public static FileAttributes attributesFor(FileType type, PosixFilePermissions permissions) {
        return new FileAttributes(type, null, null, null, permissions, null, null, null, null, new HashMap<String, String>());
    }

    public static FileAttributes attributesFor(PosixFilePermissions permissions) {
        return attributesFor(FileType.SSH_FILEXFER_TYPE_UNKNOWN, permissions);
    }

    public FileAttributes(int type,
                          Long size,
                          String owner,
                          String group,
                          PosixFilePermissions permissions,
                          Long accessTime,
                          Integer accessTimeNanos,
                          Long createTime,
                          Integer createTimeNanos,
                          Long modificationTime,
                          Integer modificationTimeNanos,
                          Acl[] acls,
                          Map<String, String> extendedData) {
        assertNotNull(type);
        this.type = type;

        this.size = size;
        this.owner = owner;
        this.group = group;
        this.permissions = permissions;
        this.accessTime = accessTime;
        this.accessTimeNanos = accessTimeNanos;
        this.createTime = createTime;
        this.createTimeNanos = createTimeNanos;
        this.modificationTime = modificationTime;
        this.modificationTimeNanos = modificationTimeNanos;
        this.acls = acls;

        assertNotNull(extendedData);
        this.extendedData = extendedData;
    }

    public FileAttributes(FileType type,
                          Long size,
                          String owner,
                          String group,
                          PosixFilePermissions permissions,
                          Long accessTime,
                          Long createTime,
                          Long modificationTime,
                          Acl[] acl,
                          Map<String, String> extendedData) {
        this(type.code, size, owner, group, permissions, accessTime, null, createTime, null, modificationTime, null, acl, extendedData);
    }

    public UnixFileType type() {
        return FileType.unixFileTypeFor(this.type);
    }

    public long size() {
        return this.size != null ? this.size : 0L;
    }

    public boolean readable() {
        return this.permissions != null && this.permissions.ownerCanRead;
    }

    public boolean writable() {
        return this.permissions != null && this.permissions.ownerCanWrite;
    }

    public long accessTime() {
        return this.accessTime != null ? this.accessTime * TIME_FACTOR : Clock.now();
    }

    public long createTime() {
        return this.createTime != null ? this.createTime * TIME_FACTOR : Clock.now();
    }

    public long modificationTime() {
        return this.modificationTime != null ? this.modificationTime * TIME_FACTOR : Clock.now();
    }

    @Override
    public String toString() {
        return "FileAttributes {"
               + "type=" + this.type
               + ", size=" + this.size
               + ", owner='" + this.owner + '\''
               + ", group='" + this.group + '\''
               + ", permissions=" + this.permissions
               + ", accessTime=" + this.accessTime
               + ", accessTimeNanos=" + this.accessTimeNanos
               + ", createTime=" + this.createTime
               + ", createTimeNanos=" + this.createTimeNanos
               + ", modificationTime=" + this.modificationTime
               + ", modificationTimeNanos=" + this.modificationTimeNanos
               + ", acls=" + Arrays.toString(this.acls)
               + ", extendedData=" + this.extendedData
               + '}';
    }
}
