#!/usr/bin/perl
#
#  $Id$
# -----------------------------------------------------------------------------
#  SM_MKLINK - small tool for creating directory and symlink 
#  for specified device and timestamp
# -----------------------------------------------------------------------------
#  Author: Alex Tsybylnik
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
#
# notes:
#   1. command line tool
#
# usage: 
#  sm_mklink <link_path>
#
# e.g.
#  sm_mklink /vasm/store/va-3.3.0/102/140302/10.0000-01
#

use strict;
use warnings;
use Data::Dumper;
use File::Basename qw(dirname);
use lib dirname(__FILE__).'/../lib';            # find  SM::Config here
use SM::Config ':all';
use NextCAM::Init qw(GetAsrv);

# CONS ------------------------------------------------------------------------
my $APL = $ENV{APL};
my $MKLINK = (split(/\//,$0))[-1];	          # the actual name of the prog
my $MOUNTPOINT = SM_MNT;
my $SM_VER = SM_VER || "va-3.3.0";
my $STORE = $MOUNTPOINT ."/store/".$SM_VER;         # path to store

#						# AF additions to avoid volumes overflow
my %asrv = GetAsrv();                           # System Identity attributes from DB

my $SPACE_LIMIT_ALLOCATION = $asrv{SM_FREE_SPACE_LIMIT} || 15;                                  # 15% is default if not set properly
my $SPACE_STOP_ALLOCATION = $SPACE_LIMIT_ALLOCATION > 5 ? $SPACE_LIMIT_ALLOCATION-5 : 1;        # 1% is minimum

# VARS ------------------------------------------------------------------------
my $vols = SM_Wheels;

# ARGS ------------------------------------------------------------------------
my $link_path = $ARGV[0];
my ($dev, $dd, $hh, $streamnum);

# SUBS ------------------------------------------------------------------------
sub usage {
    return "Usage:\n\t$MKLINK <link_path>\n";
}

sub mk_dir {
    my $dir = shift;
    return       if -d $dir;# do nothing since dir already created
    unlink($dir) if -f $dir;# unlink flat file with the same name if exists(DE978)
    mkdir($dir, 0755) || die "cannot create $dir : $!";
}

sub find_vol {
    my @s_vol=sort {
              $vols->{$a}->{LIMIT_WRITE}-$vols->{$a}->{stat_WRITE}
              <=>
              $vols->{$b}->{LIMIT_WRITE}-$vols->{$b}->{stat_WRITE}
    } grep { 
        $vols->{$_}->{ost}=~/^(Online|Degraded)$/ 
            # AF/AT: Block allocation on volume having less then $SPACE_STOP_ALLOCATION% space
            && 100*$vols->{$_}->{stat_FREE}/$vols->{$_}->{stat_SIZE} > $SPACE_STOP_ALLOCATION 
    } keys %$vols;
    die "ERR: No available volumes found!" unless @s_vol;
    my $vol = $s_vol[0];
    # AF/AT: Discourage allocation on volume having less then SPACE_LIMIT_ALLOCATION% space
    my @free = grep {
        100*$vols->{$_}->{stat_FREE}/$vols->{$_}->{stat_SIZE} > $SPACE_LIMIT_ALLOCATION
    } keys %$vols;
    $vol = $free[0] if @free;
    return $vol;
}

sub check_link {
    return 0 unless -l $link_path;
    my $src = readlink $link_path;
    return 0 unless -d $src;
    if($src =~ m|^$MOUNTPOINT/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/|) {
        my $uuid = $1;
        if(not $vols->{$uuid}->{ost}=~/^(Online|Degraded)/) {  # invalid link!
            return 0;
        }
    } else {                           # link does not point to volume, it invalid
        return 0;
    }
    return 1;
}

sub mklink {
    my $vol = find_vol;
    my $mmss = "0000";
    eval {
        unlink $link_path if -l $link_path;
        my $vpath = SM_MNT ."/$vol/".$SM_VER; # path to volume
        mk_dir ("$STORE/$dev");
        mk_dir ("$vpath/$dev");
        mk_dir ("$STORE/$dev/$dd");
        mk_dir ("$vpath/$dev/$dd");
        mk_dir ("$vpath/$dev/$dd/$hh.$mmss-$streamnum"); 
        unlink ("$STORE/$dev/$dd/$hh.$mmss-$streamnum") if -l "$STORE/$dev/$dd/$hh.$mmss-$streamnum";
        symlink("$vpath/$dev/$dd/$hh.$mmss-$streamnum","$STORE/$dev/$dd/$hh.$mmss-$streamnum") ||
            die("Cannot create symlink $STORE/$dev/$dd/$hh.$mmss-$streamnum->$vpath/$dev/$dd/$hh.$mmss-$streamnum ($!)");
        unlink ("$STORE/$dev/$dd/$hh-$streamnum") if -l "$STORE/$dev/$dd/$hh-$streamnum";
        symlink("$vpath/$dev/$dd/$hh.$mmss-$streamnum" ,"$STORE/$dev/$dd/$hh-$streamnum") ||
            die("Cannot create alias $STORE/$dev/$dd/$hh->$vpath/$dev/$dd/$hh.$mmss-$streamnum ($!)");
    };
    if ($@) {                          # catch an error
        die("ERR: dev=$dev vol=$vol: $@");
    }
}

# MAIN =======================================================================
die usage() unless $link_path;
if ($link_path=~m{^$STORE/(\w?\d+)/(\d{6})/(\d\d)-(\d+)$}) {
    ($dev, $dd, $hh, $streamnum) = ($1, $2, $3, $4, $5, $6);
}
else {
    die "Invalid link format!\n";
}

mklink unless check_link;
